我正在使用C# 5.0创建Tcp服务器,并在调用
但是,当我通过Process Explorer检查服务器的CPU使用率时,得到以下结果:
Tcp同步版本: 10%的CPU使用率 Tcp异步版本: 30%的CPU使用率其中一半是内核使用率。
此外,我通过在网络流的while循环中添加计数器来测量接收数据的次数,异步版本循环了120,000次,而同步版本则循环了2,500,000次。
就每秒收到的消息数量而言,异步版本在从3个不同的客户端接收消息时比同步版本慢15%。 为什么异步版本使用的CPU比同步版本多得多? 这是因为
连接的问题
tcpListener.AcceptTcpClientAsync
和networkStream.ReadAsync
时使用await
关键字。但是,当我通过Process Explorer检查服务器的CPU使用率时,得到以下结果:
Tcp同步版本: 10%的CPU使用率 Tcp异步版本: 30%的CPU使用率其中一半是内核使用率。
此外,我通过在网络流的while循环中添加计数器来测量接收数据的次数,异步版本循环了120,000次,而同步版本则循环了2,500,000次。
就每秒收到的消息数量而言,异步版本在从3个不同的客户端接收消息时比同步版本慢15%。 为什么异步版本使用的CPU比同步版本多得多? 这是因为
async/await
关键字吗?
异步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<AsyncTcpClientConnection> _tcpClientConnections = new List<AsyncTcpClientConnection>();
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<byte[]> _messageArrived;
private readonly TcpClient _tcpClient;
public AsyncTcpClientConnection(TcpClient tcpClient, Action<byte[]> 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();
}
}
编辑2:同步服务器
public class TcpListener : ITcpListener
{
private readonly ObserverEndpoint _serverEndPoint;
private readonly List<TcpClientConnection> _tcpClientConnections = new List<TcpClientConnection>();
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<byte[]> _messageArrived;
private readonly TcpClient _tcpClient;
private readonly Task _task;
public TcpClientConnection(TcpClient tcpClient, Action<byte[]> 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();
}
}
AsyncTcpClientConnection
中,您没有等待调用ReceiveDataFromClientAsync
。虽然与性能无关,但仍然是一个错误。 - Sergei RogovtcevReceiveDataFromClientAsync
,因为程序会永远等待,而且无法监听另一个TCP客户端。 - alexandrekow