我正在尝试使用以下代码尽可能多地挤出我的UDP数据收集套接字:
public void Start()
{
if (socket == null) Open();
this.stats.PositionServerStarted = DateTime.Now;
this.state = SocketWorkerState.Running;
AsyncBeginReceive();
}
private void AsyncBeginReceive()
{
DataPacket dataPacket = new DataPacket(socket, this.settings.IPAddress,
this.settings.Port, SocketWorker.MaxDataRead);
Interlocked.Increment(ref stats.ProcessingThreads);
socket.BeginReceiveFrom(dataPacket.BytePacket, 0,
SocketWorker.MaxDataRead, SocketFlags.None,
ref dataPacket.RemoteEndPoint, new AsyncCallback(AsyncEndReceive),
dataPacket);
}
private void AsyncEndReceive(IAsyncResult ar)
{
DataPacket dataPacket= null;
AsyncBeginReceive();
dataPacket = (DataPacket)ar.AsyncState;
dataPacket.EnteredQueue = DateTime.Now;
dataPacket.DataLength= dataPacket.SourceSocket.EndReceiveFrom(ar,
ref dataPacket.RemoteEndPoint);
Interlocked.Decrement(ref stats.ProcessingThreads);
Interlocked.Increment(ref this.stats.PacketsQueued);
ThreadPool.QueueUserWorkItem(new WaitCallback(OnPacketArrived),
dataPacket);
Interlocked.Decrement(ref this.stats.PacketsQueued);
}
private void OnPacketArrived(object packet)
{
//go ahead and process the packet
}
有没有人对如何改进这个有任何想法?从AsyncBeginReceive()
调用AsyncEndReceive()
是否被视为最佳做法?
我已经将线程池调整为
ThreadPool.SetMinThreads(20,20);
ThreadPool.SetMaxThreads(250, 250);
但如果我说实话,这似乎对表现没有太大影响。
答案 0 :(得分:1)
我个人在启动时会发布多个recv,即调用AsyncBeginReceive()
可调次数。这样你就不必等待一个recv完成,然后才能开始。在非托管术语中,总是一个好的想法是始终将异步读取挂起,以便I / O子系统可以直接读入缓冲区 - 这可能会也可能不会转化为更高的性能,但很可能转化为更少的丢失数据报。
您可能还想增加套接字的recv缓冲区大小,因为这也有助于防止丢弃的数据报。
我怀疑你必须调整线程池设置。在非托管代码中,您可以使用<处理完全加载的网络管道。 5个左右的线程使用异步I / O;那250个你的名字远远不够。
答案 1 :(得分:0)
只有当您的工作效果不佳时才进行优化,如果必须进行优化,请根据指标进行优化 - 尝试不同的方法并使用最有效的方法。
那就是说,我不相信这种方法比简单地在一个循环中有 n + 1个线程更有效,这个线程在ReceiveFrom
中阻塞然后同步完成每个数据包的处理,避免同时使用异步I / O和线程间排队。将 n 设置为瓶颈设备的数量(通常是处理器核心,但如果您严重受I / O限制,或者两者都受限,则主轴可能是您的限制资源); “+ 1”部分只是为了避免在线程正在执行其他操作时将设备空载。
我对.Net中的ThreadPool
和BeginXxx
- 异步I / O(包括完整框架和紧凑框架)都有一些非常痛苦的经历,所以我一般不建议使用它们。然后,大部分的痛苦(至少来自异步I / O)可能是由于其他人的糟糕代码造成的; ThreadPool
在紧凑框架上不可靠。 : - )
答案 2 :(得分:0)
我不认为异步是实现高性能的好方法。手动读取并在每次传递中请求更大的数据块。如果您的并发连接数较少,您甚至可以将线程专用于它们,以便套接字得到您的全面关注。与直接的方法相比,异步操作有很多开销。
如果您需要非常高的吞吐量,请考虑设置线程优先级。另请注意,.Net优先级只是相对的,因此您可能也想设置process priority。
如果您正在考虑高吞吐速度,项目属性中的优化设置会对性能产生显着影响。