高性能UDP服务.NET

时间:2011-02-10 15:49:27

标签: .net sockets udp

我正在尝试使用以下代码尽可能多地挤出我的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);

但如果我说实话,这似乎对表现没有太大影响。

3 个答案:

答案 0 :(得分:1)

我个人在启动时会发布多个recv,即调用AsyncBeginReceive()可调次数。这样你就不必等待一个recv完成,然后才能开始。在非托管术语中,总是一个好的想法是始终将异步读取挂起,以便I / O子系统可以直接读入缓冲区 - 这可能会也可能不会转化为更高的性能,但很可能转化为更少的丢失数据报。

您可能还想增加套接字的recv缓冲区大小,因为这也有助于防止丢弃的数据报。

我怀疑你必须调整线程池设置。在非托管代码中,您可以使用<处理完全加载的网络管道。 5个左右的线程使用异步I / O;那250个你的名字远远不够。

答案 1 :(得分:0)

只有当您的工作效果不佳时才进行优化,如果必须进行优化,请根据指标进行优化 - 尝试不同的方法并使用最有效的方法。

那就是说,我不相信这种方法比简单地在一个循环中有 n + 1个线程更有效,这个线程在ReceiveFrom中阻塞然后同步完成每个数据包的处理,避免同时使用异步I / O和线程间排队。将 n 设置为瓶颈设备的数量(通常是处理器核心,但如果您严重受I / O限制,或者两者都受限,则主轴可能是您的限制资源); “+ 1”部分只是为了避免在线程正在执行其他操作时将设备空载。

我对.Net中的ThreadPoolBeginXxx - 异步I / O(包括完整框架和紧凑框架)都有一些非常痛苦的经历,所以我一般不建议使用它们。然后,大部分的痛苦(至少来自异步I / O)可能是由于其他人的糟糕代码造成的; ThreadPool在紧凑框架上不可靠。 : - )

答案 2 :(得分:0)

我不认为异步是实现高性能的好方法。手动读取并在每次传递中请求更大的数据块。如果您的并发连接数较少,您甚至可以将线程专用于它们,以便套接字得到您的全面关注。与直接的方法相比,异步操作有很多开销。

如果您需要非常高的吞吐量,请考虑设置线程优先级。另请注意,.Net优先级只是相对的,因此您可能也想设置process priority

如果您正在考虑高吞吐速度,项目属性中的优化设置会对性能产生显着影响。