async / await会影响tcp服务器的性能吗?

我在C#5.0中创建一个Tcp服务器,我在调用tcpListener.AcceptTcpClientAsyncnetworkStream.ReadAsync时使用了await关键字

但是当我使用Process Explorer检查我的服务器的CPU使用率时,我得到以下结果:

Tcp Sync版本: CPU使用率为10%

Tcp异步版本: 30%的CPU使用率一半的使用是内核使用。

此外,我通过在网络流的外观中添加计数器来测量我接收数据的时间,并且异步版本循环120,000次,而同步版本循环2,500,000次。

在收到的消息/秒中,当从3个不同的客户端接收消息时,异步版本比同步版本慢15%。

为什么Async Version使用比Sync版本更多的CPU?

这是因为async / await关键字吗?

这是正常的Async Tcp服务器比它的同步速度慢吗?

编辑:这是异步tcp服务器代码的示例

 public class AsyncTcpListener : ITcpListener { private readonly ServerEndpoint _serverEndPoint; // Custom class to store IpAddress and Port public bool IsRunning { get; private set; } private readonly List _tcpClientConnections = new List(); private TcpListener _tcpListener; public AsyncTcpMetricListener() { _serverEndPoint = GetServerEndpoint(); } public async void Start() { IsRunning = true; RunTcpListener(); } private void MessageArrived(byte[] buffer) { // Deserialize } private void RunTcpListener(){ _tcpListener = null; try { _tcpListener = new TcpListener(_serverEndPoint.IpAddress, _serverEndPoint.Port); _tcpListener.Start(); while (true) { var tcpClient = await _tcpListener.AcceptTcpClientAsync().ConfigureAwait(false); var asyncTcpClientConnection = new AsyncTcpClientConnection(tcpClient, MessageArrived); _tcpClientConnections.Add(asyncTcpClientConnection); } } finally { if (_tcpListener != null) _tcpListener.Stop(); IsRunning = false; } } public void Stop() { IsRunning = false; _tcpListener.Stop(); _tcpClientConnections.ForEach(c => c.Close()); } } 

对于每个新客户端,我们创建一个新的AsyncTcpConnection

 public class AsyncTcpClientConnection { private readonly Action _messageArrived; private readonly TcpClient _tcpClient; public AsyncTcpClientConnection(TcpClient tcpClient, Action messageArrived) { _messageArrived = messageArrived; _tcpClient = tcpClient; ReceiveDataFromClientAsync(_tcpClient); } private async void ReceiveDataFromClientAsync(TcpClient tcpClient) { var readBuffer = new byte[2048]; // PacketProtocol class comes from http://blog.stephencleary.com/2009/04/sample-code-length-prefix-message.html var packetProtocol = new PacketProtocol(2048); packetProtocol.MessageArrived += _messageArrived; try { using (tcpClient) using (var networkStream = tcpClient.GetStream()) { int readSize; while ((readSize = await networkStream.ReadAsync(readBuffer, 0, readBuffer.Length).ConfigureAwait(false)) != 0) { packetProtocol.DataReceived(readBuffer, readSize); } } } catch (Exception ex) { // log } } public void Close() { _tcpClient.Close(); } } 

EDIT2:同步服务器

  public class TcpListener : ITcpListener { private readonly ObserverEndpoint _serverEndPoint; private readonly List _tcpClientConnections = new List(); private Thread _listeningThread; private TcpListener _tcpListener; public bool IsRunning { get; private set; } public TcpMetricListener() { _serverEndPoint = GetServerEndpoint(); } public void Start() { IsRunning = true; _listeningThread = BackgroundThread.Start(RunTcpListener); } public void Stop() { IsRunning = false; _tcpListener.Stop(); _listeningThread.Join(); _tcpClientConnections.ForEach(c => c.Close()); } private void MessageArrived(byte[] buffer) { // Deserialize } private void RunTcpListener() { _tcpListener = null; try { _tcpListener = new TcpListener(_serverEndPoint.IpAddress, _serverEndPoint.Port); _tcpListener.Start(); while (true) { var tcpClient = _tcpListener.AcceptTcpClient(); _tcpClientConnections.Add(new TcpClientConnection(tcpClient, MessageArrived)); } } finally { if (_tcpListener != null) _tcpListener.Stop(); IsRunning = false; } } } 

和连接

 public class TcpClientConnection { private readonly Action _messageArrived; private readonly TcpClient _tcpClient; private readonly Task _task; public TcpClientConnection(TcpClient tcpClient, Action messageArrived) { _messageArrived = messageArrived; _tcpClient = tcpClient; _task = Task.Factory.StartNew(() => ReceiveDataFromClient(_tcpClient), TaskCreationOptions.LongRunning); } private void ReceiveDataFromClient(TcpClient tcpClient) { var readBuffer = new byte[2048]; var packetProtocol = new PacketProtocol(2048); packetProtocol.MessageArrived += _messageArrived; using (tcpClient) using (var networkStream = tcpClient.GetStream()) { int readSize; while ((readSize = networkStream.Read(readBuffer, 0, readBuffer.Length)) != 0) { packetProtocol.DataReceived(readBuffer, readSize); } } } public void Close() { _tcpClient.Close(); _task.Wait(); } } 

我也有async问题,这些是我的发现: https : //stackoverflow.com/a/22222578/307976

此外,我有一个使用async示例的异步TCP服务器/客户端,可以很好地扩展。

尝试使用ReceiveInt32AsyncReceiveDataAsync的以下实现来直接接收长度为前缀的消息,而不是使用tcpClient.GetStreamnetworkStream.ReadAsync

 public static class SocketsExt { static public async Task ReceiveInt32Async( this TcpClient tcpClient) { var data = new byte[sizeof(Int32)]; await tcpClient.ReceiveDataAsync(data).ConfigureAwait(false); return BitConverter.ToInt32(data, 0); } static public Task ReceiveDataAsync( this TcpClient tcpClient, byte[] buffer) { return Task.Factory.FromAsync( (asyncCallback, state) => tcpClient.Client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, asyncCallback, state), (asyncResult) => tcpClient.Client.EndReceive(asyncResult), null); } } 

看看这是否有任何改进。 另外,我还建议将ReceiveDataFromClientAsync作为async Task方法并存储它在AsyncTcpClientConnection内返回的Task (用于状态和错误跟踪)。