2012-01-25 3 views
4

を使用して、私は非同期ネットワークストリームを返すために、デリゲートを使用して次のコード実行している:それは動作しますが、私のCPU使用率が屋根を突き破ってある高いCPU%デリゲート

static void Main(string[] args) 
{ 
    NetworkStream myNetworkStream; 
    Socket socket; 
    IPEndPoint maxPort = new IPEndPoint(IPAddress.Parse("xxx.xxx.xxx.xxx"), xxxx); 

    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); 
    socket.Connect(maxPort); 

    myNetworkStream = new NetworkStream(socket); 

    byte[] buffer = new byte[1024]; 
    int offset = 0; 
    int count = 1024; 

    string Command = "LOGIN,,,xxxx\n"; 
    ASCIIEncoding encoder = new ASCIIEncoding(); 

    myNetworkStream.BeginRead(buffer, offset, count, new AsyncCallback(OnBeginRead), myNetworkStream); 
    myNetworkStream.Write(encoder.GetBytes(Command), 0, encoder.GetByteCount(Command)); 

    while (true) { } 
} 

public static void OnBeginRead(IAsyncResult ar) 
{ 
    NetworkStream ns = (NetworkStream)ar.AsyncState; 
    int bufferSize = 1024; 
    byte[] received = new byte[bufferSize]; 

    ns.EndRead(ar); 

    int read; 

    while (true) 
    { 
     if (ns.DataAvailable) 
     { 
      string result = String.Empty; 

      read = ns.Read(received, 0, bufferSize); 
      result += Encoding.ASCII.GetString(received); 
      received = new byte[bufferSize]; 

      result = result.Replace(" ", ""); 
      result = result.Replace("\0", ""); 
      result = result.Replace("\r\n", ","); 

      Console.WriteLine(result); 
     } 
    } 
} 

を(50% Intel Core i3上で)、明らかに私はそれを間違ってやっていますが、どうですか?あなたは、メインスレッド上で継続的にループしている

おかげ

+2

'while(true)'は決して終了せず、CPUは無限にループし続けます。 –

+1

あなたがしようとしていることを明記してください。明確ではありません。しかし、あなたのCPU使用率が高いのは、あなたがきちんとした無限ループを使っているということです( 'while(true)')。 –

+0

私はIP電話から非同期フィードを返そうとしていますが、IPEndPointは電話サーバーに接続されているポートにリンクされています。 – JMK

答えて

4

あなただけが同期と無限ループで終わるその後、非同期的に非常に最初のバイトを読んでいるあなたOnBeginRead方法で事業を読みます(これは混乱する名前BTWです)。同時に、最初のバイトは現在のコードで破棄されます。

EndRead(この非同期操作でバッファに読み込まれたバイト数を返す関数)の後にデータを処理し、BeginReadで別の非同期読み込みを開始して戻ります(非同期コード!)。

編集非同期読み取りがうまくいく方法を示すサンプルを追加する:

internal class StreamHelper { 
    private readonly NetworkStream stream; 
    private readonly byte[] buffer = new byte[1024]; 

    public StreamHelper(Socket socket) { 
     stream = new NetworkStream(socket); 
    } 

    public NetworkStream Stream { 
     get { 
      return stream; 
     } 
    } 

    public byte[] Buffer { 
     get { 
      return buffer; 
     } 
    } 
} 

private static void Main(string[] args) { 
    IPEndPoint maxPort = new IPEndPoint(IPAddress.Parse("xxx.xxx.xxx.xxx"), 100); 

    Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); 
    socket.Connect(maxPort); 

    StreamHelper helper = new StreamHelper(socket); 
    helper.Stream.BeginRead(helper.Buffer, 0, helper.Buffer.Length, StreamReadCallback, helper); 

    string Command = "LOGIN,,,xxxx\n"; 
    byte[] bytes = Encoding.ASCII.GetBytes(Command); 
    // note: the write isn't async, but should maybe be converted as well 
    helper.Stream.Write(bytes, 0, bytes.Length); 

    Console.ReadLine(); // wait for a return key press 
} 

private static void StreamReadCallback(IAsyncResult ar) { 
    StreamHelper helper = (StreamHelper)ar.AsyncState; 
    // note: EndRead will throw an exception if something went wrong - you should deal with that 
    int bytesRead = helper.Stream.EndRead(ar); 
    if (bytesRead > 0) { 
     string charsRead = Encoding.ASCII.GetString(helper.Buffer, 0, bytesRead); 
     Console.Write(charsRead); 
     helper.Stream.BeginRead(helper.Buffer, 0, helper.Buffer.Length, StreamReadCallback, helper); 
    } 
} 
+0

返信いただきありがとうございます、少し詳しく説明できますか? '非同期コードにループがないのはどういう意味ですか? 'ありがとう編集:謝罪、私はあなたの返信を見て前に、このコメントを書いた! – JMK

+2

この質問に対する絶対的な唯一の正解である+1。 –

+0

非同期とは、何かする必要があるときにいつでも呼び出されることを意味します。結論としては、決してスピンウェイト(例えば何かが起こるまでループ)をしないということです。ワークフローは単純です:非同期操作を開始し、それを忘れてしまいます。しばらくすると、データが到着したか、何らかのエラーが発生したためにコールバックされます。このイベントを処理すると(コールバックはスレッドプールスレッドで処理されます)。データがあり、さらに多くのデータが必要な場合は、別の非同期操作を開始して終了します(!) - 処理するべきものがあるときはいつでも、あなたは再び呼び出されるでしょう。 – Lucero

1

while (true) { } 

これは、そのスレッドのCPUコアは、すべての回で全能力であることにします。不必要にCPU時間を取ってからスレッドを防ぐためにスリープ状態にしてみてください。

while (true) { Thread.Sleep(5000); } 
+2

いいえ、「Thread.Sleep」はバンドエイドです。 OPは意図したとおりに非同期機能を使用する必要があります。 –

1

おそらく

while (true) { } 

からあなたの主な方法の下部にあるプロセッサを回転の非効率性を置き換えます

Console.ReadLine(); 

なお、ルセロは点在している。あなたはコールバックメソッドを呼び出すスレッドを使ってinfinteループ(OnBeginRead内)に移動しています。これは間違っていると感じます。コールバックは、呼び出しスレッドが処理を続行できるように、できるだけ早く処理する必要があります。通常は、コールバック内のデータを抽出し、自分のスレッドにシグナルを送信して残りの部分を処理します。おそらくTPLスレッドがここで役立ちます。

+0

どのようにConsole.Readlineへのブロック呼び出しで無限ループを置き換えることができますか? –

+0

私はOnBeginReadで無限ループを言及していました。メインのものではありません。ここでは、呼び出しスレッドを保持しています。 – Jeb