시스템 출력 스트림 객체에 System.out을 통해 직접 접근해서 사용한다. 내가 필요한 기능만 사용 가능하므로, 다른 데코레이터 클래스를 사용해서 생기는 불필요한 작동으로 인해 소모되는 시간과 메모리를 절약할 수 있다.
시스템의 출력 스트림에 데이터를 쓰는 작업은 언제나 시간이 소모되는 작업이다. 따라서 데이터를 하나하나 써가는 것 보다는 버퍼에 한번에 쓰고 출력 스트림에 버퍼를 한번에 쓰게하는 편이 훨신 빠르다.
byte[] outBuf = new byte[1024];//1024바이트의 버퍼 //outBuf에 직접 값을 입력 예제. for(int i=0 ;i<1024; i++){ outBuf[i] = 'a';//전부 a로 채워 넣기 } System.out.write(outBuf);
1. 비교연산자의 구분 Equal과 Less, Greater Equal과 not Equal은 not을 하나 추가, 1클럭 차이나므로 어떤 CPU에서도 연산속도가 같을 수 밖에 없다. 이와 동일하게 =와 같고 > 는 not =** >, <= 일단 결론부터 말하자면, ==과 !=이 현저히 느리고 나머지 비교연산은 동등하게 빠르다. 2. 테스트 나중에 이어쓰기 3. 이유 나중에 이어쓰기
2022-10-27, 09:49
1. 시스템 출력 스트림 객체에 직접 접근. 시스템 출력 스트림 객체에 System.out을 통해 직접 접근해서 사용한다. 내가 필요한 기능만 사용 가능하므로, 다른 데코레이터 클래스를 사용해서 생기는 불필요한 작동으로 인해 소모되는 시간과 메모리를 절약할 수 있다. 2. 출력 버퍼를 쓰기 시스템의 출력 스트림에 데이터를 쓰는 작업은 언제나 시간이 소모되는 작업이다. 따라서 데이터를 하나하나 써가는 것 보다는 버퍼에 한번에 쓰고 출력 스트림에 버퍼를 한번에 쓰게하는 편이 훨신 빠르다. 3. 예제 코드 byte[] outBuf = new byte[1024];//1024바이트의 버퍼 //outBuf에 직접 값을 입력 예제. for(int i=0 ;i<1024; i++){ outBuf[i] = 'a';//전부 a로 채워 넣기 } System.out.write(outBuf);
2022-10-26, 11:44
이 포스팅은 가장 빠른 정수 입력 받기 포스팅의 연장이다. 1. 정수와 문자열 입력이 모두 존재할때 빠르게 입력받는 법 정수와 문자열이 입력으로 함께 존재하는 문제에서는 정수 입력용 커스텀 메소드를 쓰기가 까다롭다. 문자열 처리용으로 자바 입력 라이브러리를 함께 쓴다면 라이브러리와의 미묘한 처리방식 차이로 스트림에 특수문자(특히 \n나 \r)가 남아 원하지 않는 결과를 만들게 된다. 기왕 이렇게된거 문자열까지 커스텀 메소드로 작성하여 더욱 빠르게 처리하는게 좋다. 정수 입력 커스텀 메소드도 문자열 입력 커스텀 메소드가 혹시라도 남길 공백 및 개행문자를 처리하기위해 특별한 로직 필요하다. 2. 문자열 입력 커스텀 메소드 private static String readStr(int bufSize) throws IOException{ byte[] bytes = new byte[bufSize]; int i=0; while(true) { int input = System.in.read(); if(input != '\n' && input != '\r' && input != ' ' ) { bytes[i++] = (byte)input; break;//앞 공백 제거 후 시작. } } while(true) { int input = System.in.read(); if(input == '\n' || input == '\r' ) { return new String(bytes, 0, i); }else bytes[i++] = (byte)input; } } 문자열앞에 개행(운영체제별 개행방법 모두 고려)과 공백이 연속해서 존재할 경우도 고려. 운영체제 또는 입력 인코딩에 따라 메소드 종료 후에 InputStream에 개행문자가 남을 가능성이 있다. 2번의 이유로 연달아 쓸때 오류를 발생 시키지 않기 위해 1번 조건을 만족시키는 설계를 하게되었다. 3. 수정된 정수 입력 커스텀 메소드 private static int readInt() throws IOException { int sum; boolean isNegative = false; while(true) { int input = System.in.read(); if(input != '\n' && input != '\r' && input != ' ' ) { if (input == '-') isNegative = true; else { sum = input-'0'; break;//앞 공백만 제거 후 시작. 숫자가 아닌 문자가 들어간건 안걸러줌. } } } while (true) { int input = System.in.read(); if (input == '\n' || input == ' '|| input=='\r') return isNegative ? sum * -1 : sum; else sum = (sum * 10) + input - '0'; } } 정수 입력앞에 개행(운영체제별 개행방법 모두 고려)과 공백이 연속해서 존재할 경우도 고려. 1번 조건에 해당하지 않는 문자들은 모두 정수로 가정하고 처리하므로 입력에 정수앞에 공백과 개행 이외의 문자가 남아있을때는 문자열 입력 받는 커스텀 메소드로 해당 문자들을 읽어들인 후에 정수를 읽도록 해야한다. 4. 22년 11월 24일 추가로 개선된 버전 변경 세부사항 try구문을 메소드 내부에 삽입하여 static에서도 선언될 수 있게 함. IOException 대신 Exception으로 변경하여 import 제거. readInt()의 분기 조건을 단순화함. private static String readStr(int bufSize){ try { byte[] bytes = new byte[bufSize]; int i=0; while(true) { int input = System.in.read(); if(input != '\n' && input != '\r' && input != ' ' ) { bytes[i++] = (byte)input; break;//앞 공백 제거 후 시작. } } while(true) { int input = System.in.read(); if(input == '\n' || input == '\r' ) { return new String(bytes, 0, i); }else bytes[i++] = (byte)input; } }catch(Exception e) { e.printStackTrace(); } return null; } private static int readInt() { try { int sum; boolean isNegative = false; while(true) { int input = System.in.read(); if(input >= '0') { sum = input-'0'; break;//앞 공백만 제거 후 시작. 숫자가 아닌 문자가 들어간건 안걸러줌. }else if(input == '-') {//-뒤에 숫자가 나올때까지의 공백은 무시함. isNegative = true; } } while (true) { int input = System.in.read(); if (input < '0') return isNegative ? sum * -1 : sum; else sum = (sum * 10) + input - '0'; } }catch(Exception e) { e.printStackTrace(); } return 0; }
2022-10-23, 16:39
1. 빠른 정수 입력 스트림 읽기의 필요성 백준 알고리즘 문제를 풀다보면 정수로 구성된 일련의 데이터를 받아서 처리해야할 때가 있다. 백준은 입력과 출력 시간도 알고리즘 수행시간에 포함되다 보니 입, 출력 시간 절약이 아주 중요하다. 사람들이 입력 스트림을 읽는 방법은 크게 4 가지이다. Scanner 사용 BufferedReader 사용 사칙연산을 사용하는 커스텀 메소드 사용 비트연산을 사용하는 커스텀 메소드 사용 이중 가장 빠른 것은 사칙 연산을 사용하는 커스텀 메소드이다. 각 방법을 빠른 순으로 나열하면 사칙연산 사용 커스텀 메소드 비트연산 사용 커스텀 메소드 BufferedReader Scanner 커스텀 메소드들의 성능은 거의 같다. BufferedReader는 커스텀 메소드의 두배정도 걸린다. Scanner는 BufferedReader의 두 배이상 걸린다. 테스트 수행 결과 2. 각 방법의 코드 및 사용법 2.1. Scanner 클래스 임포트 import java.util.Scanner; 객체 생성 및 정수 입력 스트림 읽기 Scanner sc = new Scanner(System.in); //생략 sc.nextInt() //생략 sc.close(); 2.2. BufferedReader 클래스 임포트 import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.StringTokenizer; 객체 생성 및 정수 입력 스트림 읽기 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //생략 //한줄에 여러개의 입력 정수가 공백 하나를 기준으로 나뉘어서 들어올때 StringTokenizer st = new StringTokenizer(br.readLine(), " "); Integer.parseInt(st.nextToken()); //입력이 한줄에 하나씩일때 Integer.parseInt(br.readLine()); //생략 sc.close(); 2.3. 사칙연산을 이용하는 커스텀 메소드 메소드 선언 static int readInt() throws IOException { int sum = 0; boolean isNegative = false; while (true) { int input = System.in.read(); if (input == '\n' || input == ' ') return isNegative ? sum * -1 : sum; else if (input == '-') isNegative = true; else sum = (sum * 10) + input - '0'; } } 정수 입력 스트림 읽기 readInt(); 2.4 비트연산을 이용하는 커스텀 메소드 메소드 선언 private static int readInt() throws Exception { int c, n = System.in.read() & 15; boolean isNegative = n == 13; if (isNegative) n = System.in.read() & 15; while ((c = System.in.read()) > 32) n = (n 32) n = (n << 3) + (n << 1) + (c & 15); return isNegative ? ~n + 1 : n; } } 3.2. 테스트 데이터 준비 테스트 입력 데이터 준비, 및 복사해놓기. 한줄에 1~10쓰고 1000번 반복한 전체 데이터를 복사. 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 ... 1 2 3 4 5 6 7 8 9 10 3.3 테스트 프로그램 실행 및 데이터 붙여넣기 3초간의 sleep시간안에 입력 스트림에 복사해둔 10000개의 숫자 데이터를 붙여넣기 후 enter, 프로그램은 3초의 sleep이 끝난후 startTime에 타임스템프를 찍고 스트림을 읽기 시작한다. ... 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 시작 5
2022-10-20, 11:04
1. IoC 소개 IoC(Inversion of Control), 제어의 역전소프트웨어 설계에서의 프로그래밍 원칙으로, 프레임워크에서 정의된 제어의 흐름(flow of Control)을 사용, 프레임워크가 사용자 정의 코드를 필요에 따라 호출하여 사용하게 한다. 기존 절차적 프로그래밍 에서의 제어의 흐름과 비교하면 제어가 역전\\되었다. 1.1. 제어의 역전 기존 절차적 프로그래밍에서는 어떤 작업을 처리하기 위해 사용자 정의 코드에 제어의 흐름(선언과 반복 및 분기문, 함수와 재사용가능한 라이브러리 호출등의 절차)을 사용자가 직접 정의하던 방식과 비교해서 IoC 원칙에 따른 설계는 프레임워크가 작업을 수행하기 위해 프레임워크에 정의되어있는 제어의 흐름대로 프로그램을 수행, 필요에 따라 사용자 정의 코드 를 (마치, 재사용 라이브러리를 사용하듯)호출하게 된다. 즉, 제어의 흐름이 사용자에게서 프레임워크로 넘어가게 되었고 이를 제어의 역전이라고 말한다. 2. OOP에서의 IoC 객체 지향 프로그래밍에서 IoC(Inversion of Control)은 프로그래밍 원칙으로, 모든 객체들에 대한 제어를 제어만을 담당하는 특별한 객체가 하는 형태이다. 2.1. OOP의 제어(Control) 객체들에 대한 제어란, 간단히 말해, 객체들의 생성과 메소드 호출, 소멸등 과 같은 생명주기를 관리하는 것을 말한다. 2.2 DI(Dependency Injection) DI(Dependency Injection), 의존성 주입은 객체 지향 프로그래밍에서의 IoC의 구현인 디자인 패턴이다. DI 패턴에서 모든 객체는 자신이 의존성을 가지는 다른 객체에 대한 참조를 외부 코드인 Injecter로 부터 주입 받는다. 객체는 자신이 의존성을 가지는 다른 객체들의 생명주기에 관여할 수 없다. 즉, 커스텀 클래스 내부에서는 다른 객체의 생성 및 초기화나 소멸 시기를 독립적으로 지정할 수가 없다. 관련 포스트 링크 : DI(Dependency Injection), 의존성 주입
programming principle
ioc
2022-10-14, 02:25
1. @HotSpotIntrinsicCandidate 역할 1.1. HotSpot에서 내장 함수로 치환될 수 있는 JDK의 정적 메소드들을 표시 HotSpot JVM에서는 최적화 기법중 하나로 JDK의 일부 정적 메소드들에 대한 고성능의 내장 함수(intrinsic function)들을 제공한다. JDK 9부터 등장한 @HotSpotIntrinsicCandidate은 JDK의 특정 메소드들이 HotSpot의 내장 함수로 치환될 수 있음을 나타낸다. 표시를 할뿐, 실제로 @HotSpotIntrinsicCandidate를 통해 javac의 Annotation Processor가 내장 함수 또는 네이티브 코드로 변환해주는 기능은 없다. 해당 기능은 JIT의 역할이기 때문이다. : 손으로 직접 최적화 작성한 어셈블리어 혹은 컴파일러 IR로 구성 1.2. JDK 사용자가 HotSpot의 내장함수 기능을 최대한 활용 할 수 있게 함 JDK를 활용한 개발을 할때, 개발자는 별도의 스펙을 찾아보지 않고 정적 메소드상단의 @HotSpotIntrinsicCandidate의 유무만 보고도 Hotspot의 내장 함수기능을 제공 받는지를 알 수가 있다. 따라서 개발자는 코드에 @HotSpotIntrinsicCandidate가 선언된 정적 메소드로 대체 가능한 코드는 최대한 대체시켜서 HosSpot JVM에 최적화된 프로그래밍이 가능하다. HotSpot JVM은 기본 JDK배포에 포함되는 JVM의 표준이므로 해당 어노테이션을 활용한 최적화된 프로그래밍에 익숙해져야 한다. 2. @HotSpotIntrinsicCandidate은 Internal 하다 @HotSpotIntrinsicCandidate은 JDK의 코어 라이브러리에서만 선언 가능하고 사용자 코드에서는 선언이 불가하다. @HotSpotIntrinsicCandidate의 선언은 오로지 JDK을 만들고 배포하는 개발자 및 개발사들이 고려해야할 사항이다. The {@code @HotSpotIntrinsicCandidate} annotation is internal to the Java libraries and is therefore not supposed to have any relevance for application code. OpenJDK11 JavaDoc 3. @HotSpotIntrinsicCandidate은 Intrinsify를 보장하진 못한다 HotSpot은 구동되는 타겟 OS, 벤더에 따라 그 구현이 조금씩 다르다. 따라서 각 구현마다 내장 함수 목록도 조금씩 달라서 @HotSpotIntrinsicCandidate이 쓰여있더라도 하드웨어에 설치된 HotSpot에서는 내장 함수로 치환이 안될 수 있다. \* The HotSpot VM defines (internally) a list of intrinsics. Not all intrinsic \* are available on all platforms supported by the HotSpot VM. Furthermore, \* the availability of an intrinsic on a given platform depends on the \* configuration of the HotSpot VM (e.g., the set of VM flags enabled). \* Therefore, annotating a method with {@code @HotSpotIntrinsicCandidate} does \* not guarantee that the marked method is intrinsified by the HotSpot VM. OpenJDK11 JavaDoc 4. @HotSpotIntrinsicCandidate는 반드시 표시되어야 한다 Java 9부터 등장한 @HotSpotIntrinsicCandidate는 JDK코어 라이브러리 개발자로 하여금 @HotSpotIntrinsicCandidate를 반드시 쓰게 하기위해서, JIT 컴파일러에서 해당 어노테이션을 가진 메소드들만 내장 함수치환 기능을 제공하도록 제한된다. OpenJDK 11의 JavaDoc에 따르면 HotSpot JVM의 JIT를 실행할 때 CheckIntrinsics 플레그를 통해 내장 함수 치환 기능을 제공하는데, 해당 플레그가 참일 때(Default는 참), 클래스를 로드하는 시점에서 해당 어노테이션을 가지고 있는 메소드가 HotSpot의 내장 함수 리스트에 있는지를 검사한다고 한다. 해당 사항에 대해선 OpenJDK와 JDK는 같은 스펙을 공유한다. \* If the {@code CheckIntrinsics} VM flag is enabled, the HotSpot VM checks \* (when loading a class) that (1) all methods of that class that are also on \* the VM's list of intrinsics are annotated with {@code @HotSpotIntrinsicCandidate} \* and that (2) for all methods of that class annotated with \* {@code @HotSpotIntrinsicCandidate} there is an intrinsic in the list. \* \* @since 9 OpenJDK11 JavaDoc 관련 이슈 링크. 관련 블로그 링크 관련 블로그 링크2
java
jvm
hotspot
hotspotintrinsiccandidate
2022-10-14, 16:58