4

while ループにある NetworkStream から読み取っています。問題は、CPU 使用率が 100% になっていることです。これが起こらないようにする方法はありますか?

これが私がこれまでに持っているものです:

    while (client != null && client.Connected)
            {

                NetworkStream stream = client.GetStream();
                data = null;

                try
                {
                    // Check if we are still connected.
                    if (client.Client.Poll(0, SelectMode.SelectRead))
                    {
                        byte[] checkConn = new byte[1];

                        if (client.Client.Receive(checkConn, SocketFlags.Peek) == 0)
                        {
                            throw new IOException();
                        }
                    }

                    if (stream.DataAvailable)
                    {
                        //Read the first command
                        WriteToConsole("Waiting for next command");
                        data = ReadStringFromClient(client, stream);
                        WriteToConsole("Received Command: " + data);
                    }
                }

... コードは続きます...

ReadStringFromClient コード:

   private string ReadStringFromClient(TcpClient clientATF, NetworkStream currentStream)
    {
        int i;
        string builtString;
        byte[] stringFromClient = new byte[256];

        if (clientATF.Connected && currentStream.CanRead)
        {

            i = currentStream.Read(stringFromClient, 0, stringFromClient.Length);
            builtString = System.Text.Encoding.ASCII.GetString(stringFromClient, 0, i);

        }

        else
        {
            return "Connection Error";
        }

        return builtString;

    }
4

3 に答える 3

9

あなたのコードには多くの...ノイズが含まれています。あなたはそれを必要としません。

CPU 負荷が 100% になる理由は、データが利用可能になるのをスピン待機しているためです。その必要はありません。Readデータが利用可能になるまでブロックします。NetworkStreamまた、受信するデータの各チャンクを再作成する必要もありません。

StreamReaderを使用すると、コードを大幅に簡素化できます。

using (var reader = new StreamReader(new NetworkStream(socket))
{
    char[] buffer = new char[512];
    int received;
    while ((received = reader.Read(buffer, 0, buffer.Length)) > 0)
    {
        string s = new string(buffer, 0, received);
        Console.WriteLine(s);
    }
}

Readデータが利用可能になるまでブロックします。接続が有効な間、コードはループします。char バッファーに読み込む代わりに ReadLine を使用すると、コードをさらに簡素化できます。

データが利用可能になるまでスレッドをブロックしたくない場合は、非同期読み取りをご覧ください。

于 2010-10-11T22:32:33.033 に答える
6

100% の CPU 使用率が表示されている理由は、常に何かを実行しているためです。これは、遅延のない無限の while ループの結果です。

基本的なセマンティクスは次のとおりです。

  1. クライアントが接続されているかどうかを確認する
  2. クライアントをポーリングする
  3. データが利用可能かどうかを確認する
  4. データを読む
  5. ステップ 1 に戻る

あなたはこのループにいるので、それが何であれ、常に何かをしています。最も簡単なセマンティックは、ループの最後で Thread.sleep() を実行することです。これにより、多くの変更を加える必要がなくなります。ただし、そのスリープ時間の遅延を導入することになり、実際には適切な方法ではありません (ただし、状況に適している場合があります)。

適切な方法は、高性能サーバーが必要な場合、または 1 つ以上のソケットが接続されているときに適切な低 CPU を使用するものが必要な場合は、非同期ソケットについて学習することです。簡単な Google 検索を行うことは、学ぶのにおそらく最善の方法です。特に優れた記事をすぐに思い出すことはありません。非同期 IO の利点は、基本的に、何かをする必要がある場合にのみ CPU 時間を使用することです。データが受信されると、必要な処理を行うためにメソッドが呼び出されます。

于 2010-10-11T22:40:39.867 に答える
5

これは、CPU に何かを行うように常に要求しているためです。つまり、ストリームに利用可能なものがあるかどうかを確認します。

これは、適切に対処する方法を学ぶ必要がある非常に一般的なパターンです。これは非同期 IO と呼ばれます。幸いなことに、.NET フレームワークには広範なサポートがあり、CPU を常に 100% 使用しなくても、目的を簡単に達成できます。

大きな問題は、コードが無限ループで実行されており、常に呼び出しclient.Client.Poll(0, SelectMode.SelectRead)が行われ、すぐに応答が返されることです。代わりに、ネットワーク ストリームから読み取れるデータがある場合など、何か興味深いことが発生したときに通知するようにフレームワークに依頼する必要があります。そして、それを行う方法はたくさんあります。1 つの方法は、NetowrkStream のBeginReadメソッドを使用することです。

クライアント アプリケーションの非同期ソケット プログラミングの例を次に示します。

于 2010-10-11T22:32:37.147 に答える