2011-09-28 3 views
1

CSV 파일 (문자열)의 실제로드/구문 분석을 최적화해야합니다. 내가 아는 가장 좋은 방법은 load-in-place 알고리즘이며, JNI와 파싱 된 csv 데이터로 만들어진 파일에서 직접 데이터를로드하는 C++ dll을 사용하여 성공적으로 사용했다.자바 문자열 최적화 - 현장 배치 알고리즘

거기서 멈췄다면 좋겠지 만 그 계획을 사용하면 데이터를 더 이상 파싱하지 않아도 15 % 빨라졌습니다. 첫 번째 이유는 Java 클라이언트가 jstring을 사용하므로 char *에서 jstring으로 실제 데이터를 다시 변환해야하기 때문입니다.

변환 단계를 무시하고 데이터를 jstring 객체에 직접로드 (더 이상 변환하지 않음)하는 것이 가장 좋습니다. 따라서 장소에로드 된 데이터를 기반으로 데이터를 복제하는 대신 jstring은 메모리 덩어리를 직접 가리킬 수 있습니다 (데이터는 char 대신 jchars로 작성됩니다). 진짜 나쁜 점은 가비지 컬렉터가 데이터를 수집하지 않도록해야한다는 것입니다 (아마도 참조를 유지함으로써)?하지만 실행 가능해야합니다. 아니요? ..

1로드 자바의 데이터 (더 이상 JNI) 및 문자열을 생성하기 위해로드 된 데이터를 가리키는 문자를 사용하지만 필요 :

나는 내가 그 작업을 수행하는 두 가지 옵션이 생각 String을 만들 때 데이터 복제를 막는 방법을 찾으십시오.

2 jni를 계속 사용하여 "수동으로"jstring 변수를 만들고 설정하고 가비지 수집기 옵션이 올바르게 설정되어 있는지 확인하십시오. 예를 들어 :

이이
jstring * str = (jstring *)&loadedinplacedata[someoffset]; 
return * str; 

내가 알고 있어요 아니라고 : 그것이 가능하지만 그냥 마음을 파일에 직접 jstring으로 저장하고 그렇게 다시로드하지 않는다면

jstring str; 
str.data = loadedinplacedata; // assign data pointer 
return str; 

확실하지 않음 일반적인 자바 일이지만, 자바가 충분히 확장 가능하다는 것을 확신 할 수 있습니다. 그리고 나는이 문제에 대한 선택권이 정말로있는 것 같지 않습니다 ... 프로젝트는 이미 3 세이며 일해야합니다. = S 이것은 JNI 코드 (C++)되어

:

const jchar * data = GetData(id, row, col); // get pointer of the string ends w/ \0 
unsigned int len = wcslen((wchar_t*)data); 
// The best would be to prevent this function to duplicate the data. 
jstring str = env->NewString(data, len); 
return str; 

참고 : 위의 코드 대신 UTF8 유니 코드 데이터를 이용하여 (대신 15)는 20 % 더 빠르게 이루어 (대신 해 NewStingUTF의 newstring 인수로 쓰여진) . 이것은 해당 단계를 제거하거나 최적화 할 수 있다면 성능이 상당히 좋아질 수 있음을 보여줍니다.

+1

이 로딩이란 무엇입니까? 복사가 디스크 IO보다 오래 걸리면 놀랄 것입니다. 실제로 바보 같은 일이 없다고 가정하면됩니다. –

+0

- 1) 전체 파일을 동시에 메모리에 저장해야합니까? - 2) JNI를 사용하는 이유는 무엇입니까? – claymore1977

+0

일반적으로 dev 환경에서는 .jar 파일과 파일에서 직접로드됩니다. 따라서 이미로드되어 있어야하므로 디스크 IO가 거의 없다고 가정 할 수 있습니다. 동시에 메모리에 모두 필요하지 않지만 jar 파일의 일부이므로 파일이 이미 있어야합니다. JNI는 포인터를 사용할 수있게합니다 ...하지만 C++로 더 많은 XP가 있기 때문에 Java의 기능 중 일부를 잘못 이해했을 수도 있습니다. 데이터의 복사를 막을 수있는 방법이 있습니까 (예 : 메모리상의 위치를 ​​기반으로 참조를 다시 사용하는 것과 같은)? – MasterPlanMan

답변

0

음 ... 내가 해킹하지 않는 한 Java에서 "지원"하지 않는다고 생각합니다. GetStringCritical을 사용하여 실제 문자 배열 주소를 얻은 다음이를 찾을 수 있다고 믿습니다. 문자 수를 줄이는 등 "안전한"프로그래밍을 넘어서는 길입니다.

가장 좋은 해결 방법은 자바에서 해시 테이블을 만들고 내 데이터 파일을 만드는 동안 처리 된 고유 식별자를 사용하는 것입니다 (.intern()과 유사). 문자열이 해시 테이블에 없으면 dll을 통해 쿼리하고 해시 테이블에 저장합니다.

데이터 파일 : numrow, NUMCOLS, 각 셀에 대한 은 \ 0

으로 끝나는 문자열을 추가, 각 셀 (문자열을 가리키는 메모리에 내 경우에는 오프셋)를 정수 값을 추가 오프셋 값을 사용하여 문자열 생성 및 문자열 쿼리의 수를 어느 정도 최소화 할 수 있습니다. 나는 dref 내부 문자열을 유지하기 위해 globalref를 사용하여 시도했지만 4 배 느리게 만들었다.

0

나는 JNI와 함께 일한 적이 없지만, CharSequence를 구현하는 커스텀 클래스를 돌려주는 것이 합리적 일까? String 대신에 Comparable < CharSequence> 같은 몇개의 다른 인터페이스를 돌려주는 것은 의미가있는 것인가? 그렇게하면 데이터 손상 문제가 발생할 확률이 줄어들 것 같습니다.

+0

시도해 볼 가치가 있습니다. 예를 들어, 데이터 복제에 의존하지 않고로드 된 데이터 (메모리 스트림이나 바이트 배열과 같은 것)에서 재사용 할 수있는 클래스를 만들 수 있다면 가능합니다. 하지만 그것은 대부분의 String 클래스 함수를 다시해야한다. 그 클래스를 해시 테이블과 호환되게 만드는 것이 쉬운 것입니까? – MasterPlanMan

+0

@Adam - 물론 - hashcode() 및 equals()를 구현하십시오. 그들은 크기면에서 사소하지만, 그럼에도 불구하고 신경 써야합니다. JDK 문자열 소스를 참조하십시오. 당신은 아마도 toString()을 원할 것이다. –

+0

문자열 클래스의 자식을 대신 정의 할 수 있습니까? 왜냐하면 문자열 객체를 필요로하는 곳이 많기 때문입니다. 그래서이 클래스를 생성하면 데이터의 중복을 연기 할 수 있습니다. = S else 문자열을 요청한 곳의 코드를 변경하고 charsequence를 요구하도록 변경해야합니다 . – MasterPlanMan

0

먼저 C++ 버전이 15 % 빠르게 실행되는 이유와 그 성능 향상이 Java로 직접 변환 될 수없는 이유를 이해해야합니다. Java에서 코드를 15 % 빠르게 작성할 수없는 이유는 무엇입니까?

문제를 살펴 봅니다. C++ dll을 사용하여 구문 분석을 제거했습니다. (왜 이것이 자바로 이루어지지 않았을까?).그리고 나는 그것을 이해 :

직접 당신이 수정 jstrings 접촉에서 가비지 컬렉터를 방지 할
  • (그들에 대한 참조를 유지하여)을 jstrings의 내용을 조작 할 것을 제안하고
    1. 하고, 따라서 잠재적으로 JVM의 동작을 수정하고 결국 가비지 수집을 수행 할 때 가비지 수집기를 사용하지 않을 수 있습니다.

    가비지 수집을 허용하기 전에 이러한 참조를 수정하겠습니까?

    만약 당신이 자신의 메모리 관리를 제안한다면, 왜 당신은 전혀 자바를 사용하고 있습니까? 왜 순수한 C++에서 그것을하지 않습니까?

    Java를 계속 사용하기를 원한다고 가정하면 String을 작성할 때 문자열 자체가 새로운 Object이지만 그것이 가리키는 데이터가 반드시 필요하지는 않습니다. String.intern()을 호출하여이를 테스트 할 수 있습니다.

    public static void main(String[] args) { 
        String s3 = "foofoo"; 
    
        String s1 = call("foo"); 
        String s2 = call("foo"); 
    
        System.out.println("s1 == s2=" + (s1 == s2)); 
        System.out.println("s1.intern() == s2.intern()=" + (s1.intern() == s2.intern())); 
        System.out.println("s1.intern() == s3.intern()=" + (s1.intern() == s3.intern())); 
    
        System.out.println("s1.substring(3) == s2.substring(3)=" + (s1.substring(3) == s2.substring(3))); 
        System.out.println("s1.substring(3).intern() == s2.substring(3).intern()=" + (s1.substring(3).intern() == s2.substring(3).intern())); 
    } 
    
    public static String call(String s) { 
        return s + "foo";   
    } 
    

    이 생산 : 다음 코드를 사용하여

    s1 == s2=false 
    s1.intern() == s2.intern()=true 
    s1.intern() == s3.intern()=true 
    s1.substring(3) == s2.substring(3)=false 
    s1.substring(3).intern() == s2.substring(3).intern()=true 
    

    그래서 당신은 String 객체가 다르지만, 데이터는 실제 바이트 수없는 것을 볼 수 있습니다. 그래서 당신의 수정은 실제로 그 관련성이 없을 수도 있습니다, JVM은 이미 당신을 위해 그것을하고있을 수 있습니다. 그리고 jstring의 내부를 수정하기 시작하면, 이것이 엉망이 될 수도 있습니다.

    제 제안은 알고리즘 측면에서 할 수있는 것을 찾아내는 것입니다. 순수 자바로 개발하면 Java가 항상 더 빠릅니다. & JNI가 결합되었습니다. 순수 Java로 더 나은 솔루션을 찾을 수있는 기회가 훨씬 많습니다.

  • +0

    프로젝트가 Java로되어 있기 때문에 (3 살입니다) 특정 케이스의 경우 jni를 거치지 않으면 C++로 변경할 수 없습니다. 나는 C++ 대신 java를 유지하려고한다. 내 목표는 15 % 빨라진 코드가 아니라는 것입니다. 더욱 빨라야합니다. 로드 인 플레이스 (load-in-place)는 그렇게하기위한 좋은 방법입니다.하지만 나는 새로운 제안을 할 수 있습니다. =) 이제는 내 자신의 메모리 관리를하고 싶지 않지만 어떤 문제도 방지 할 수 있다고 가정했습니다.하지만 볼 수 있듯이 외부 버퍼를 사용하여 String 데이터를 설정할 수 있습니까? 데이터의 중복을 막을 수 있습니까? – MasterPlanMan

    +0

    또한, 다른 "형식"과 문자열의 위치를 ​​포함하는 색인을 사용하여 java를 통해 구문 분석 할 수있는 양을 줄이는 방법이 있지만 최상의 구문 분석은 없습니다. 그것은 C++에서 다소 쉽습니다. 그러나 자바에서 (적어도 나를 위해) 할 수 있습니다. 따라서 여러분들에게 제 질문입니다. – MasterPlanMan

    +0

    "그러나 가리키고있는 데이터가 반드시"필요하지는 않습니다. "- 정확히 내가하려는 것입니다. char [], byte [], jni 등에서 오는 데이터를 고려하여 가리키는 데이터를 어떻게 지정합니까? (이미 정의 된 문자열이 아님) 그렇게 할 수 있다면 자바로 데이터를로드하면됩니다 (그렇지 않으면 더 이상 사용할 수 없습니다!). 중복되지 않은 문자열 데이터를 직접 지정해야합니다. – MasterPlanMan