【问题标题】:High Performance UDP Service .NET高性能 UDP 服务 .NET
【发布时间】:2011-02-10 15:49:27
【问题描述】:

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

有人对如何改进有任何想法吗?从AsyncEndReceive() 调用AsyncBeginReceive() 是否被认为是最佳实践?

我已将线程池调整为

ThreadPool.SetMinThreads(20,20);
ThreadPool.SetMaxThreads(250, 250);

但老实说,这似乎对性能没有太大影响。

【问题讨论】:

    标签: .net sockets udp


    【解决方案1】:

    我个人会在您启动时发布多个recv,即调用AsyncBeginReceive() 可调整的次数。这样您就不必等待一个 recv 完成,然后才能开始下一个。在非托管术语中,总是有一个异步读取挂起通常是一个好主意,这样 I/O 子系统可以在可能的情况下直接读取到您的缓冲区 - 这可能会或可能不会转化为更高的性能,但很可能会转化为更少的丢失数据报.

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

    我怀疑您是否必须调整线程池设置。在非托管代码中,您可以使用异步 I/O 处理具有

    【讨论】:

    • 我在 msdn 中找不到 AsyncBeginReceive()。你有什么可以建议的参考吗?谢谢。
    • 这是原始问题代码中的一个方法。它调用socket.BeginReceiveFrom() 这可能是你想要使用的:)
    【解决方案2】:

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

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

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

    【讨论】:

    • 如何从 UDP 套接字读取“更大的块”,你要么得到整个数据报,要么没有。
    • 您从流中读取。如果你在内部使用小块大小,你会经历更多的迭代。每次调用操作系统的成本和缓冲它的所有代码的成本。此外,如果没有适当的优化,GC 将会有一个聚会(你必须在外面等到它完成)......通常过于本地化的临时数组初始化以处理流。
    【解决方案3】:

    仅当您拥有的功能不够好时才进行优化,如果您必须优化,请根据指标进行优化 - 尝试不同的方法并使用最有效的方法。

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

    我在 .Net(完整和紧凑的框架)中使用基于 ThreadPoolBeginXxx 的异步 I/O 有过一些非常痛苦的经历,所以我一般不推荐使用它们。再说一次,大部分痛苦(至少来自异步 I/O)可能是由于其他人的糟糕代码造成的。 ThreadPool 在紧凑的框架上并不可靠。 :-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-08
      • 1970-01-01
      相关资源
      最近更新 更多