2012-01-25 3 views
4

я бегу следующий кусок кода, который использует делегат для возврата асинхронного сетевого потока:High 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); 
     } 
    } 
} 

Это работает, но мое использование CPU через крышу (50% на Intel Core i3), поэтому, очевидно, я делаю это неправильно, но как это сделать?

Благодаря

+2

'while (true)' никогда не будет завершен, и он будет поддерживать циклический цикл работы процессора бесконечно. –

+1

Опишите, что вы пытаетесь сделать, поскольку это не ясно. Ясно, однако, что источником высокой загрузки процессора является то, что вы используете жесткий бесконечный цикл ('while (true)'). –

+0

Я пытаюсь вернуть асинхронный канал с IP-телефона, IPEndPoint связан с портом на сервере вызовов, который подключен к телефону – JMK

ответ

4

Вы только чтение самого первых байт асинхронно, после чего вы оказываетесь в бесконечном цикле с синхронизацией операций чтения в методе OnBeginRead (это путаное имя BTW). В то же время эти первые байты отбрасываются в вашем текущем коде.

Вы должны обработать данные после EndRead (который является функцией, возвращающей сколько байт были прочитаны в буфер в этой асинхронной операции), а затем начать другую асинхронное чтение с BeginRead и возвратом (нет зацикливания в асинхронном код!).

Edited добавить образец, показывающий, как асинхронная чтение будет работать:

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

Async означает, что вы получите обратный вызов, когда вам нужно что-то сделать. Вывод заключается в том, что вы никогда не выполняете ожидание (например, цикл, пока что-то не произойдет). Рабочий процесс прост: вы запускаете операцию async и забываете об этом. Через некоторое время вы получите обратный вызов (либо из-за того, что данные были получены, либо возникла какая-либо ошибка), и в это время вы обрабатываете это событие (обратный вызов будет обрабатываться в потоке пула потоков). Если у вас есть данные, и вы ожидаете большего, то вы начнете новую операцию async и закройте (!) - вы снова будете вызваны, когда есть что-то, что нужно обработать - и т. д. – Lucero

1

Вы постоянно зацикливание на главной теме:

while (true) { } 

Это приводит к тому, процессорное ядро ​​этой нити на полную мощность в любое время. Попробуйте спать, чтобы предотвратить нить от принятия процессорного времени излишне:

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

Нет. «Thread.Sleep» - это бандажная помощь. OP должен использовать функции async, поскольку они предназначены. –

1

Возможно заменить неэффективность спиннинга процессора в нижней части основного метода из

while (true) { } 

в

Console.ReadLine(); 

Кстати, Лусеро находится на месте. Вы переходите в цикл infinte (в OnBeginRead) с потоком, который вызывает метод обратного вызова. Это кажется неправильным. Обратные вызовы должны обрабатываться как можно скорее, чтобы обработать вызывающий поток. Обычно вы извлекаете данные в обратном вызове и отправляете сигнал в свой поток, чтобы обработать остальные. Возможно, здесь будет использоваться поток TPL.

+0

Каким образом вы могли бы заменить бесконечный цикл блокирующим вызовом на Console.Readline ...? –

+0

Я упоминал бесконечный цикл в OnBeginRead. Не тот, что в основном. Здесь мы поднимаем вызывающий поток. – Jeb