2011-09-10 9 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の簡単な言葉を使ってください。コード例で、私は単なるJAVA初心者です。ありがとうございました

+1

IfあなたはビデオゲームのためのJava初心者のサーバーバックエンドです。私はあなたに幸運を祈っています。とてもたくさん! :) – cheeken

+0

私は基本を持っていることを心配しないでください。私は長い間vb6プログラマでありました。私はちょうどこの1つで助けが必要です – Reacen

+0

クイックコメント; ['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ánUbietoが示唆のように)文字のいくつかのバッファに読み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

Umm、それは '\ u0000'に分割されません – Reacen

+0

あなたが 'packet.split( '\ 0');'を追加して配列にループする場合 –

+0

これは_inより速いと思いますか? .read()?お願いします? – Reacen

0

大きなバッファ(1K)を使用できるほど多くのバイトを読み込みます。 "ターミネーター"が見つかったかどうか確認してください( '\ u0000'、 '\ n'、 '\ r')。そうでない場合は、(ソケットを読み取るために使用されていたよりも大きい)一時バッファにコピーし、再度読み込み、「ターミネータ」が見つかるまで一時バッファにコピーします。すべての必要なバイトを取得したら、一時バッファを最後のバッファにコピーして処理します。残りのバイトは、「次の」メッセージとみなされ、一時バッファの先頭にコピーされます。

+0

私は迷っています。私はあなたに従うことができるようにいくつかのコードをお願いしますか? – Reacen

+0

なぜ再処理して余分なデータをコピーすると改善するのでしょうか? BufferedReader *はすでに4096文字の*大きな*バッファを使用して*できるだけ多くのバイトを読み込みます。 – EJP

2

BufferedReaderから大量のチャンク、または一度に1文字を読むと、パフォーマンスに大きな問題はありません。

コードで特定のホットスポットとして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

関連する問題