使用委托时CPU%高

时间:2012-01-25 13:59:19

标签: c# asynchronous delegates

我运行以下代码,使用委托来返回异步网络流:

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);
        }
    }
}

它可以工作,但是我的CPU使用率已经达到顶峰(英特尔酷睿i3的50%),所以很明显我做错了,但是怎么做?

由于

3 个答案:

答案 0 :(得分: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);
    }
}

答案 1 :(得分:1)

您正在主线程上连续循环:

while (true) { }

这使得该线程的CPU核心始终处于满容量状态。尝试睡眠以防止线程不必要地占用CPU时间:

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

答案 2 :(得分:1)

也许用

替换主方法底部旋转处理器的低效率
while (true) { }  

Console.ReadLine();

顺便说一句,Lucero就是现货。您正在使用调用回调方法的线程进入infinte循环(在OnBeginRead中)。这感觉不对。应该尽快处理回调以让调用线程继续进行处理。通常,您将在回调中提取数据并将信号发布到您自己的线程以处理其余的数据。也许TPL 线程在这里会有所帮助。