2011-09-10 3 views
2

최적화에 대한 도움이 필요합니다. 나는 JAVA로 만든이 오픈 소스 게임 서버를 개선하려고 노력 중이다. 각 플레이어는 자신의 스레드를 가지고 있으며, 각 스레드는 다음과 같이 간다 :이 코드는 바보 너무 여러 번 들었습니다한 번에 1 바이트 씩 소켓 읽기, 이것을 변경하는 방법,

BufferedReader _in = new BufferedReader(new InputStreamReader(_socket.getInputStream())); 

String packet = ""; 
char charCur[] = new char[1]; 

while(_in.read(charCur, 0, 1)!=-1) 
{ 
    if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r') 
    { 
     packet += charCur[0]; 

    }else if(!packet.isEmpty()) 
    { 
     parsePlayerPacket(packet); 
     packet = ""; 
    } 
} 

를하고 프로파일 링 할 때 나는 각 바이트를 읽고 추가 것을 볼 수 있기 때문에 동의 packet += ""을 사용하면 바보 같고 느립니다.

나는 이것을 개선하고 싶지만 어떻게 해야할지 모르겠다. 나는 '\u0000을 기반으로 패킷을 분리해야하기 때문에 이보다 더 느려지는 것을 두려워한다. ', '\n' 또는 '\r'을 사용하여 구문 분석 할 수 있습니다. 그리고 나는 3 번 나누는 것이 verry slow임을 안다.

누군가 내 아이디어를 줄 수 있습니까? 또는 이것을위한 코드 조각? 그것은 내 하루를 만들 것입니다.

설명을 원하시면 verry simple words와 코드 예제를 사용하십시오. 저는 자바 초보자입니다. 고맙습니다

+1

If 당신은 비디오 게임을위한 자바 초보자 서버 백엔드입니다, 나는 당신에게 행운을 빌어 요. 제비 뽑기와 제비 뽑기! :) – cheeken

+0

기본을 가지고 있어도 걱정하지 마라. 오랫동안 vb6 프로그래머로 일 해왔다. 나는이 도움이 필요하다. – Reacen

+0

quick comment; ['StringBuilder'] (http://download.oracle.com/javase/6/docs/api/java/lang/StringBuilder.html)를 사용하면 느린''packet + = charCur [0];을 피할 수 있습니다. 루프 (각 루프에 문자열을 할당 함) –

답변

1

아마도 BufferedReader의 readLine() 메소드를 살펴 봐야 할 것입니다. 문자열을 읽은 것처럼 보입니다. BufferedReader.readLine()을 호출하면 다음 줄이 생깁니다 (줄 바꿈/줄 바꿈 제외). 이 같은

뭔가 :

String packet = _in.readLine(); 
while(packet!=null) { 
    parsePlayerPacket(packet); 
    packet = _in.readLine(); 
} 

은 그냥 스트림 중 하나가 폐쇄되거나 줄 바꿈/라인 피드가있을 때까지 차단 구현 내의 readLine()를하는 것처럼.

편집 : 예, '\ 0'을 (를) 분할하지 않습니다. 당신은 가장 좋은 건 아마 내가 그 디버깅하지 않았다 (데이비드 Oliván Ubieto이 시사하는 것처럼) 문자의 일부 버퍼에 읽어 PushbackReader,

PushbackReader _in = new PushbackReader(new InputStreamReader(_socket.getInputStream())); 
StringBuilder packet = new StringBuilder(); 
char[] buffer = new char[1024]; 
// read in as much as we can 
int bytesRead = _in.read(buffer); 

while(bytesRead > 0) { 
    boolean process = false; 
    int index = 0; 
    // see if what we've read contains a delimiter 
    for(index = 0;index<bytesRead;index++) { 
     if(buffer[index]=='\n' || 
      buffer[index]=='\r' || 
      buffer[index]=='\u0000') { 
      process = true; 
      break; 
     } 
    } 
    if(process) { 
     // got a delimiter, process entire packet and push back the stuff we don't care about 
     _in.unread(buffer,index+1,bytesRead-(index+1)); // we don't want to push back our delimiter 
     packet.append(buffer,0,index); 
     parsePlayerPacket(packet); 
     packet = new StringBuilder(); 
    } 
    else { 
     // no delimiter, append to current packet and read some more 
     packet.append(buffer,0,bytesRead); 
    } 
    bytesRead = _in.read(buffer); 
} 

입니다,하지만 당신은 아이디어를 얻을.

String.split ('\ u0000')을 사용하면 개행/줄 바꿈이 스트림을 통해 전송 될 때까지 '\ u0000'으로 끝나는 패킷이 처리되지 않습니다. 어떤 종류의 게임을 작성하고 있기 때문에 들어오는 패킷을받는 즉시 처리하는 것이 중요하다고 생각합니다.

+0

음, 그건 '\ u0000' – Reacen

+0

에 분할하지 않을 것입니다. 여러분이'packet.split ('\ 0');'을 덧붙여 배열 위에 루프하면 –

+0

이것은 _in보다 빠르다고 생각합니까? .read()? 부디? – Reacen

0

큰 버퍼 (1K)를 사용할 수있는만큼 많은 바이트를 읽으십시오. "터미네이터"('\ u0000', '\ n', '\ r')가 있는지 확인하십시오. 그렇지 않다면 임시 버퍼 (소켓 읽기에 사용 된 것보다 큼)에 복사하고 다시 읽은 다음 "터미네이터"가 발견 될 때까지 임시 버퍼에 복사하십시오. 필요한 모든 바이트가 있으면 임시 버퍼를 "최종"버퍼로 복사하고 처리합니다. 나머지 바이트는 "다음"메시지로 간주되어 임시 버퍼의 시작으로 복사되어야합니다.

+0

내가 길을 잃었 어, 내가 너를 따라갈 수 있도록 코드를 좀 줄래? – Reacen

+0

왜 재 처리와 여분의 데이터 복사로 개선이 이루어질까요? BufferedReader *는 이미 4096 자의 * 더 큰 * 버퍼를 사용하여 * 할 수있는만큼의 바이트를 읽습니다. – EJP

2

BufferedReader에서 큰 덩어리 또는 한 번에 한 문자 씩 읽는 경우 중요한 성능 문제는 없습니다.

프로파일에서 코드의 특정 핫스팟으로 BufferedReader.read() 메서드를 식별하지 않으면 코드를 간단하고 읽기 쉽도록 만들고 시간을 최적화하지 않아도됩니다.

특정 사례를 들어

:

  • 네 그 코드는 조금 구식이지만,
  • 더는 성능 측면에서 차이를 많이 만들 가능성이 없습니다.

실제 성능 병목은 네트워크 자체 일 가능성이 큽니다. 이 문제를 해결하기 위해 할 수있는 응용 프로그램 수준의 기능이 있지만 궁극적으로 종단 간 네트워크 연결이 지원하는 속도로만 데이터를 보내고받을 수 있습니다. BufferedReader.read() :


내 프로파일 링 결과는에서오고 있다고 말하고있다. 정말 그게 무슨 뜻 이죠?

정말 Socket의 읽기 방법에 시간을 소비하고 있습니까? 그렇다면 실제 문제는 응용 프로그램 스레드가 네트워크 패킷 도착을 기다리는 데 많은 시간을 소비하고 있다는 것입니다. 그런 경우라면 클라이언트가 할 수있는 유일한 일은 네트워크가 너무 많은 작은 패킷을 다룰 필요가 없도록 클라이언트와 서버 측 플러시 수를 줄이는 것입니다. 응용 프로그램에 따라 실행 불가능할 수도 있습니다. 그것이 성능에 큰 차이를 만들 것입니다 생각 ...은 "패킷"하지 않는 한 일반적으로 긴 문자 수백하지

BufferedReader _in = new BufferedReader(
     new InputStreamReader(_socket.getInputStream())); 

StringBuilder packet = new StringBuilder(); 
int ch; 

while ((ch = _in.read()) != 1) { 
    if (ch != '\u0000' && ch != '\n' && ch != '\r') { 
     packet.append((char) ch); 
    } else if (!packet.isEmpty()) { 
     parsePlayerPacket(packet.toString()); 
     packet = new StringBuilder(); 
    } 
} 

그러나 나는 할 :

다음과 같이 난 당신의 코드를 작성하는 것 . (패킷을 읽는 동안 생성되는 임시 문자열의 수를 줄이는 것이 중요합니다. read 호출에서 실시간을 덜 보내는 간단한 방법은 없다고 생각합니다.)

+0

필자의 프로파일 링 결과는 BufferedReader.read()에서 발생한다고 말합니다. 정말 그게 무슨 뜻 이죠? – Reacen

관련 문제