2013-10-04 3 views
2

Java 애플리케이션 내에서 호출되는 groovy eval (string) 메소드의 성능 문제의 원인을 추적하려고합니다. 다음 코드를 실행하면; 나는 ~ 걸리는Groovy 스크립트 eval (문자열) 메소드의 성능 문제

String first = "['one','two','three']"; 
String pattern = "test = " + first; // "identical" String to first approach 
engine.eval(pattern) 

실행하는 30 + 밀리 다음과 같은 말한다면

String pattern = "test = ['one','two','three']"; 
engine.eval(pattern) 

그것은, 그러나에 사실상 시간 (0이 1ms로)

를 실행합니다.

더 나쁜 것은 수천 번의 호출 후에 두 구현 사이의 시간 델타보다 훨씬 덜 우려하지만 60-70ms만큼 높을 것입니다.

왜 이런 일이 발생했는지에 대한 설명/이것을 피하는 방법에 대한 제안? Java 및/또는 Groovy 컴파일러와 관련이 있고 컴파일() 메서드를 살펴보기 시작했으나 기존 코드가 작동하도록 만드는 간단한 방법이 있다면 더 선호 할 것입니다. 방법).

+0

정확히 해시 기반 캐시를 만들 수 있지만, 문자열 인)가 평가에 전달하고있는 시간 (기준 동일 (사과하는 경우 그게 당신이 말하는거야) ... – user1251193

+1

어떻게 엔진을 구성합니까? JSR-223을 사용하고 있습니까? 그렇다면 http://groovy.codehaus.org/JSR+223+Scripting+with+Groovy와 마지막 단락 인'엔진이 스크립트 함수에 대한 기본 하드 참조 당 유지합니다. '를 참조하십시오. 그루비는 여기에서 최적화 할 수 있습니다. 연결을 사용하면 표현식이 새로운 문자열로 취급 될 수 있으며 캐시 된 스크립트가 아닌이 차이가 발생할 수 있습니다. –

답변

0

eval은 모든 언어로 악명이 높으며 속도가 느리고 종종 "eval is evil"에서 떨어져 있어야한다고 권고합니다. 그러나 코드에서 문자열 결합이 평가 자체보다는 속도 저하를 일으키는 것으로 보입니다.

여전히 몇 밀리 초가 걱정할 필요가 없습니다. 코드에서 성능 병목 현상을 일으키는 것으로 확인 했습니까? 코드를 미세 조정하면 미래에 버그와 불명확 한 코드가 생성 될 수 있으며 이는 훨씬 더 나쁜 영향을 미칩니다.

+0

슬프게도 예, 몇 초에서 5 분 이상 걸리는 시간을 수천 번이나 잠재적으로 불러올 수있는 무언가입니다. 더 나쁜 것은 동일한 작업을 두 번째 실행하는 것은 내가 언급 한 평가의 실행 시간이 늘어남에 따라 10 분 (다음 15-20 분)이 걸린다는 것입니다. 두 번째 문제를 해결하면 5 분만 살 수는 있지만 스크립트를 컴파일하는 것만 큼 간단하지는 않습니다. 각 호출에서 동일하게 보장되지는 않기 때문입니다. 우리는이 메소드를 애플리케이션 전반에 걸쳐 사용합니다. 성능은 문제가 아닙니다. 식의 접두어를 사용해야하는 유일한 경우입니다 ... Thx – user1251193

+0

@ user1251193 흠, 대신 StringBuilder를 사용할 수 있습니까? 그것은 당신이하는 연결의 수에 따라 약간의 시간을 절약 할 수 있습니다. – Igor

+0

그것은 내 마음을 넘어 섰지 만 그것은 단지 하나의 연결 일 뿐이며 지연은 그 이전보다 평가 내에서 발생하는 것처럼 보입니다. 나는 그것이 지연을 일으키는 정적 대 동적 컨텍스트의 더 많은 것이라고 생각하지만, 차이를 만드는 경우 그것을 시도하고 업데이트를 게시 할 것입니다. 다시 한 번 감사드립니다 ... – user1251193

0

호출 시간을 어떻게 측정하고 있습니까? 가능한 경우, 나는 각 부분 (String building과 eval())을 측정하여 어느 부분이 시간이 걸리고 어떤 것이 반복 횟수에 따라 증가 하는지를 결정할 것입니다. 반복 횟수가 늘어남에 따라 시간이 증가한다고 말하기 때문에 가비지 수집을 살펴보십시오. 첫 번째 경우는 단일 문자열을 사용합니다. 나중에 반복 할 때마다 새 String을 작성하므로 메모리를 소비합니다. 힙 한계에 맞춰 실행 중일 수 있습니다.

VisualVM은 매우 유용한 도구 중 하나입니다.

+0

폴 감사합니다. 타이밍은 eval()에 대한 것입니다. 이 문제는 PermGen이 채워지는 문제로 시작되었으므로 며칠 동안 프로파일 러에 적극적으로 참여했습니다 (YourKit 사용). 어느 시점에서 나는 GC를 의심했지만, 수업을 언로 드하고 힙보다 PermGen (매우 막강하고 집중적 임)을 삭제하기 때문에 (GB 중 무료). 나는 ~ 1ms에서 실행되는 대체 접근법을 생각해 냈습니다. (잠시 후에 게시 할 예정입니다.)하지만 아직도 누군가가이 동작에 대한 근본적인 이유를 설명 할 수 있기를 바라고 있습니다. 이것은 나에게 여전히 수수께끼입니다. – user1251193

+0

@ user1251193 전체 벤치 마크를 공유 할 수 있습니까? 그것이 사용되는 방법에 따라 고정 문자열은 인턴 될 수 있으며 Groovy eval은 스크립트를 한 번만 컴파일 한 다음 두 번째 반복을 위해 캐시 된 인스턴스를 사용하는 최적화를 가질 수 있습니다. 연결은 새로운 String을 생성하도록합니다. Groovy와 Java 버전도 흥미로울 것입니다. –

+0

나는 실제 코드를 공유 할 자유가 없지만 위에 표시된 코드로 문제를 재현했다. 타이밍은 eval 호출 전후의 로그에 기록을 통해 측정된다. ,있을 경우 포함). 타이밍 차이는 엔진 자체가 많은 반복을 통해 캐시 되어도 매우 호출 (1ms 미만의 연결과 30ms 미만의 연결)에서 발생하며 후속 호출 후에 어느 방법 으로든 타이밍이 향상되지 않습니다 (이 경우 정확히 같은 문자열에 대해 a를 실행하고 있습니다). – user1251193

0

http://visualvm.java.net/은 궁극적으로 우리는 그렇게

eval("['one','two','three']") 

반환 정확히,

Object test = engine.eval(first) 

engine.eval("test = " + "['one','two','three']") // see text above for exact syntax 
Object test = engine.get("test") 

에 해당한다는 인식 아직 전혀에서 효율적으로 시간을 실행하지 않습니다.

동적 인 패턴을 사용하면 eval() 성능에 큰 영향을 미칩니다.하지만 Java 및/또는 Groovy 런타임 요소에 대한 깊은 이해를 바탕으로 그 위에 어떤 빛이라도.

도움을 주신 모든 분들께 감사드립니다. 감사합니다.

ps.

2

https://github.com/groovy/groovy-core/blob/master/subprojects/groovy-jsr223/src/main/java/org/codehaus/groovy/jsr223/GroovyScriptEngineImpl.java?source=cc을 보면 문자열을 클래스에 매핑하기위한 캐시를 찾을 수 있습니다. 문제는 ManagedConcurrentMap이 기본적으로 ID 해시 맵이라는 점입니다. 동일한 문자열을 반복해서 사용하면 이후의 실행을 위해 컴파일이 건너 뛰기 때문에 빠른 것입니다. 문제 버전은 매번 새로운 문자열을 생성하므로 항상 매번 컴파일해야하므로 매번 새로운 클래스가 생성됩니다. 방지하는 방법에

이 : 나는 그것이 컴파일러의 의심되거나 실행 시간을 최적화 문제 왜

+0

대단히 blackdrag! 당신은 수수께끼를 해결했습니다. 아마도 몇 가지 가능성이 있습니다. 당신이 그루비 내부 구조를 아주 잘 이해하고있는 것처럼 보이기 때문에 (나는 당신의 게시물을 많이 읽었습니다.) 그들이 표준지도가 아닌 신분 맵을 사용하는 것이 이상한 것처럼 보이지 않습니까? 이 글을 통해 우리는 전체 애플리케이션에서 Groovy를 사용하는 것을 보면서 바쁘다. 효과적인 문자열은 본질적으로 동일하기 때문에 코드가 캐시 될 것으로 예상되는 곳이 많이있다. 우리가 너무 많은 클래스를 생성하고/너무 많은 permgen을 사용하는 것은 당연한 일입니다. 다시 한 번 감사드립니다! – user1251193

+0

잠시 시간을 내면 다른 질문이 생깁니다.이 소식에 비추어 볼 때, 우리는 항상 동일한 String을 반환하기 위해 자신의 조회 맵을 유지하려고합니다. 잠재적 인 문제/우려 사항이 있습니까? 그렇지 않다면, 우리에게 일이 어떻게 진행되는지에 대한 업데이트를 게시 할 것입니다 ... – user1251193

+0

늦게 답변드립니다 ... 동시성과 기억을 염두에두고있는 한 사용자 정의 조회지도에는 아무런 문제가 없습니다. 그 두 가지는 사소하지 않습니다. 왜 IdentityMap ... 솔직하게 ... 나는이 변화를 만들었고 나는 그 부분을 간과했을지도 모른다라고 생각하고있다. .. 나에 대한 수치 – blackdrag

관련 문제