2010-01-20 3 views
4

java.nio.charset.Charset.decode(..)/encode(..)을 수행하는 더 빠른 방법을 아는 사람은 누구입니까?java.nio.charset.Charset.decode (..)/encode (..)에 대한 빠른 대안

현재 내가 사용하고있는 기술의 병목 중 하나입니다.

[편집] 특히, 내 응용 프로그램에서 Java 기술보다 하나의 세그먼트가 JNI 솔루션으로 변경되었습니다 (Java 기술보다 내 필요에 가장 적합한 C++ 기술이 있었기 때문에).).

이 변경으로 인해 속도가 크게 저하되었으며 (CPU 사용량이 크게 증가했습니다).

내가 사용했던 JNI 솔루션을 자세히 살펴보면 Java 응용 프로그램은 byte []를 통해 C++ 응용 프로그램과 통신하고 있습니다. 이 바이트 []는 자바 측에서 Charset.encode (..)에 의해 생성되고 C++ 측에 전달됩니다. 그런 다음 byte []가있는 C++ 응답이 Charset.decode (..)를 통해 Java 측에서 디코딩됩니다.

프로파일 러에 대해이 작업을 실행하면 Charset.decode (..) 및 Charset.encode (..) 모두 JNI 솔루션의 전체 실행 시간과 비교하여 상당히 긴 시간이 걸린 것을 알 수 있습니다. JNI 솔루션은 매우 빠르게 정리할 수있는 솔루션이기 때문에 나중에 일정을 정리하면 전체 애플리케이션을 프로파일 링합니다 .-)).

내 문제에 관해 더 자세히 읽고 나면 Charset.encode (..) 및 decode (..)에서 알려진 문제로 보이며 Java7에서 해결되고 있습니다. 그러나 Java7 로의 전환은 몇 가지 제약으로 인해 현재로서는 (나에게는) 옵션이 아닙니다.

누군가 내가 Java5 솔루션/대안을 알고 있는지 묻는 이유는 무엇입니까? (죄송합니다. Java5가 더 빠르다고 언급 했음에 틀림 없습니까?) :-)

+1

기능 요구 사항은 무엇입니까? (더 큰 그림) – BalusC

+1

특정 문자 세트? 최근 릴리스에서는 UTF-8 디코드가 더 빨라야합니다. I/O가 실제 병목 현상이 될 것으로 예상됩니다. –

+1

'decode()'의 바이트의 소스와 문자의 목적지는 무엇입니까? 'encode()'의 문자 소스와 바이트의 목적지는 무엇입니까? 성능 문제는 실제 인코딩 또는 디코딩 프로세스보다 입력 및 출력 할당 및 복사와 더 관련 될 수 있습니다. – seh

답변

6

encode()decode()에 대한 javadoc은 이것이 편리한 메소드임을 분명히합니다. 예를 들어, encode()에 대한이 캐릭터 세트로 표현 된 바이트 유니 코드 문자를 인코딩

편리한 메소드입니다.

가 연속 사이 인코더를 캐시 할 수 있기 때문에 캐릭터 연사시에 메소드 호출은 그것이 잠재적으로 더 효율적임을 제외 같이 표현

cs.newEncoder() 
    .onMalformedInput(CodingErrorAction.REPLACE) 
    .onUnmappableCharacter(CodingErrorAction.REPLACE) 
    .encode(bb); 

를 동일한 결과를 반환 호출.

언어가 다소 모호하지만, 이러한 편리한 방법을 사용하지 않으면 성능이 향상 될 수 있습니다. 를 다시 사용하고 만들기를 한 번 인코더를 구성 :

CharsetEncoder encoder = cs.newEncoder() 
    .onMalformedInput(CodingErrorAction.REPLACE) 
    .onUnmappableCharacter(CodingErrorAction.REPLACE); 

encoder.encode(...); 
encoder.encode(...); 
encoder.encode(...); 
encoder.encode(...); 

그것은 항상 자바 독을 읽어 지불, 당신은 이미 답을 알고 있다고 생각하는 경우에도 마찬가지입니다.

+1

자바 1.6에서 (적어도)'CharSet.encode (...)'의 구현은 스레드 로컬을 사용하여 캐시 된 인코더를 사용하고 매번 설정 호출 ('onMalformed ... '등)을 반복합니다. 자신의 캐싱을 수행하면 스레드 로컬 가져 오기의 오버 헤드와 설정 호출 만 저장하게됩니다. 이것은 아마도 중요하지 않습니다 ... 비록 프로파일 러가 당신에게 말해야 만합니다. –

+0

공정한 포인트. 여기에는 멀티 스레드 사용 사례가 있습니다. – skaffman

+0

사실, javadoc과 Charset의 소스 코드도 읽었습니다. 그리고 1.5 스레드 로컬 버퍼링이 있습니다. 그리고 느린 속도를 낼 수있는 코드와 프로파일러는 없습니다. 제 추측으로 범인은'for (;;)'입니다. –

1

바이트 배열의 문자열을 "꽉 짜는"이유는 거의 없습니다. utf-16 문자열을 매개 변수로 사용하는 C 함수를 작성하는 것이 좋습니다. 이렇게하면 변환 할 필요가 없습니다.

+0

좋아, 그 중 하나를 시도해 보겠습니다. –

2

첫 부분 - 일반적으로 배열을 JNI 코드로 전달하는 것은 좋지 않습니다. GC 때문에 Java는 복사 배열을 복사해야합니다. 가치있는 배열에서 두 번 복사됩니다 - 돌아 오는 길에 JNI 코드와 도중에 :

그 때문에 Buffer 클래스 계층 구조가 도입되었습니다.

Charser#newDecoder 돌아갑니다 CharsetDecoder하는 Charset에 따라 CharBufferByteBuffer을 comvert하는 데 사용할 수 있습니다 : 물론 자바 팀 dev/디코드 문자를 인코딩 할 수있는 좋은 방법을 만듭니다. 기본 방법에는 두 가지가 있습니다.

CoderResult decode(ByteBuffer in, CharBuffer out, boolean endOfInput) 
CharBuffer decode(ByteBuffer in) 

최대 성능을 얻으려면 첫 번째 방법이 필요합니다. 내부에 숨겨진 메모리 할당이 없습니다.

인코더/디코더가 내부 상태를 유지할 수 있으므로주의해야합니다 (예 : 2 바이트 인코딩에서 매핑하고 입력 버퍼의 문자 수가 절반 인 경우). 또한 인코더/디코더가 스레드 안전하지 않음