2010-08-04 5 views
3

일반 :
나는 일부 서버 측 (먼 일)에서 모든 시간 (절대 루프 결말을)/"시장"데이터를 수신 인용 소켓 클라이언트를 쓰고 있어요.
데이터를 청크로 나누어서 사용할 수 있습니다.
각 청크에는 약 200자를 포함하므로 배열로 변환해야합니다.
청크가 분할 된 후 List (여기에는 No Problems)로 구문 분석됩니다.자바 CLI 응용 프로그램 성능

문제 :
CPU 사용이 실행 10 분 후 40 %에 도달한다.
문제를 격리 할 수있었습니다.
모든 청크를 json으로 변환해야합니다.
그래서 문제를 해결하는 실제 코드를 제공하고 있습니다.
이 코드는 300-400 MS마다 실행됩니다.
이 코드를 건너 뛰면 전체 시스템의 CPU 사용률은 1 % -2 %가됩니다.

참고 :
나는이 스레드를 읽고하지만 난 거기에 모든 솔루션을 볼 수 없습니다.
Is it better to reuse a StringBuilder in a loop?

코드 :

private static StringBuffer jsonVal = new StringBuffer(); 

    public static String toJson(List<QuotesData> quotesData) { 
     // Empty variable 
     jsonVal.delete(0, jsonVal.length()); 
     jsonVal.append("{"); 
     synchronized (quotesData) { 
      for (QuotesData quote : quotesData) { 

       jsonVal.append("\"").append(quote.getSymbol()).append("\":[{"); 
       jsonVal.append("\"ask\":\"").append(quote.getAsk()).append(
         "\","); 
       jsonVal.append("\"bid\":\"").append(quote.getBid()).append(
         "\","); 
       jsonVal.append("\"time\":\"").append(quote.getDateTime()) 
         .append("\"}],"); 

      } 
      jsonVal.append("}"); 
      String returnString = jsonVal.toString(); 
      return returnString.toString().replace("}],}", "}]}"); 
     } 
    } 
+0

(제목과는 반대로) StringBuilder 대신 StringBuffer를 사용하는 이유가 무엇입니까? 그 수준에서 동기화합니까? – leonbloy

답변

2

먼저 나는 성능 저하가 어디 정확히을 찾아 낼 JProfiler와 또는 JConsole의, JDK6에 포함 모두를 사용하는 것이 좋습니다 것입니다.

CPU 사용량을 알지 못하면 synchronized을 피할 것입니다. 나는 append이 의심 스럽다. static 로컬 jsonVal도 제거하여 청소하십시오.

public static String toJson(final List<QuotesData> quotesData) { 
    final List<QuotesData> theData = new ArrayList<QuotesData>(quotesData); 
    StringBuffer jsonVal = new StringBuffer(); 
    jsonVal.append("{"); 
    for (QuotesData quote : quotesData) { 
     jsonVal.append("\"").append(quote.getSymbol()).append("\":[{"); 
     jsonVal.append("\"ask\":\"").append(quote.getAsk()).append(
       "\","); 
     jsonVal.append("\"bid\":\"").append(quote.getBid()).append(
       "\","); 
     jsonVal.append("\"time\":\"").append(quote.getDateTime()) 
       .append("\"}],"); 

    } 
    jsonVal.append("}"); 
    String returnString = jsonVal.toString(); 
    return returnString.toString().replace("}],}", "}]}"); 
} 

Gson과 같은 JSON 라이브러리를 사용해보십시오. 코드가 훨씬 간단 해집니다. 필요한 경우 출력을 조정할 수 있습니다

private static final Gson gson = new Gson(); 
public static String toJson(final List<QuotesData> quotesData) { 
    return gson.toJson(new ArrayList<QuoteData>(quotesData)); 
} 
+0

감사합니다. 목록 은 복제 가능하지 않습니다. – fatnjazzy

+0

@fatnjazzy 감사합니다. 나는 대답을 수정했다. –

0

몇 가지 제안 :

  • 코드를 프로파일, 그것은 당신에게 핫스팟을 표시해야합니다.
  • StringBuffer 대신 StringBuilder을 사용하십시오. StringBuffer은 동기화되었으므로 StringBuilder은 동기화되지 않습니다.
  • synchronized 문이 정말로 필요합니까? 그렇지 않은 경우 제거하십시오.
  • toString()은 return 문에 필요하지 않습니다. 제거 할 수 있습니다.
  • replace() 메서드가 필요 없도록 코드를 수정하면 returnString 길이가 길면 값이 비쌀 수 있습니다.
  • 이전에 루프를 지우기 전에 새로운 StringBuffer 개체를 만들어보십시오.
  • 문자열 즉 return returnString.intern()
+0

예, 이건 스레드 안전 영역입니다 ... 내가 사기를 줬어 ... 변화 없음. – fatnjazzy

0

내 손님의 StringBuilder가 지속적으로 크기가 조정되고 있다는 점이다의 interned 값을 반환하려고합니다. 얼마나 많은 quotesData가 있습니까? for 루프 앞에 크기가있는 StringBuilder를 만드는 것이 좋습니다.

StringBuffer jsonVal = new StringBuffer(quotesData.size()*200); //the 200 is on top of my head. Do a few loop to see what is the average length of a QuotesData. 

그런데 대신 StringBuilder를 사용 해본 적이 있습니까? StringBuffer와 같아서 스레드로부터 안전하다는 오버 헤드를 뺀 것입니다 (StringBuffer는 동기화되고 StringBuild는 그렇지 않습니다).

0

정상적으로 최적화 된 고전적인 사례입니다. 특히 300-400ms마다 호출하는 경우 동일한 문자열 버퍼를 다시 작성해야하는 데 비용이 많이 드는 것은 아닙니다. 위의 코드는 새로운 스레드마다이 300ms를 할당 지수 성장 하지만리스트는 엄청난이며 직렬화하는이 300ms 인수 :

나는 가능한 모든 시나리오를 해결하기 위해 노력할 것이다. 이 경우에 당신은 기본적으로 당신의 자원을 질식 시키며 응용 프로그램이 충돌하기 전에 그것은 시간 문제 일뿐입니다. 이 경우 CPU가 계속해서 상승해야합니다. 해결책은 될 것이다에 :

  1. 제한
  2. 동시에 JSON 개체를 구축하고 그래서 하나의 JSON은 다음 걸리지 구축 결과를 병합 응용 프로그램을 죽이지 않도록 동시에 실행할 수있는 스레드 수 300ms.

속도 향상 확인 목록은 정말 목록이 아니라 목록 인터페이스로 구현 큐의 일종하지 않은 내가 있으리라 믿고있어 수단 복제 가능한되지 않도록.

public static final int JSON_LENGTH = 250; //you probably know this 

public static String toJson(final List<QuotesData> quotesData) { 
    jsonVal = new StringBuilder(JSON_LENGTH * quotesData.size()); 
    jsonVal.append("{"); 
    synchronized (quotesData) { 
     for (QuotesData quote : quotesData) { 

      jsonVal.append("\"").append(quote.getSymbol()).append("\":[{") 
      .append("\"ask\":\"").append(quote.getAsk()).append("\",") 
      .append("\"bid\":\"").append(quote.getBid()).append("\",") 
      .append("\"time\":\"").append(quote.getDateTime()).append("\"}],"); 

     } 
     // much much faster than replace 
     jsonVal.setCharAt(jsonVal.length()-1, '}'); 
     return jsonVal.toString(); 
    } 
} 

변화의 대부분은 화장품, 그리고 나는 JIT는 이미 최적화 것이라고 확신 : 나는이 작업을 수행 할 것입니다 그래서 동기화를 떠나. 차이점은 StringBuilder를 사용하고 매번 새로운 문자열을 만들고 .replace()을 사용하지 않는 것입니다. 그러나 첫 번째 설명 (기하 급수적 인 성장)에 적합하지 않으면 문제가 여기에 있다는 것을 의심하지 마십시오. 먼저 구현 목록을 살펴 보겠습니다.

+0

Asaf, thanks ... 아무것도 도움이되지 않습니다. 심지어 스레드 풀을하려고했는데 ... 재미있는 점은 PHP에서 동일한 코드가 있고 더 오랜 시간 동안 더 빠르게 작동한다는 것입니다. CPU 문제없이 ... 어쨌든. 도다 ... 감사 – fatnjazzy

관련 문제