我应该对“延迟关键”线程使用线程关联吗?

时间:2013-03-08 13:48:46

标签: c# multithreading low-latency

在我的HFT交易应用程序中,我有几个地方从网络接收数据。在大多数情况下,这只是一个只接收和处理数据的线程。以下是此类处理的一部分:

    public Reciver(IPAddress mcastGroup, int mcastPort, IPAddress ipSource)
    {

        thread = new Thread(ReceiveData);

        s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        s.ReceiveBufferSize = ReceiveBufferSize;

        var ipPort = new IPEndPoint(LISTEN_INTERFACE/* IPAddress.Any*/, mcastPort);
        s.Bind(ipPort);

        option = new byte[12];
        Buffer.BlockCopy(mcastGroup.GetAddressBytes(), 0, option, 0, 4);
        Buffer.BlockCopy(ipSource.GetAddressBytes(), 0, option, 4, 4);
        Buffer.BlockCopy(/*IPAddress.Any.GetAddressBytes()*/LISTEN_INTERFACE.GetAddressBytes(), 0, option, 8, 4);
    }

    public void ReceiveData()
    {
        byte[] byteIn = new byte[4096];
        while (needReceive)
        {
            if (IsConnected)
            {
                int count = 0;
                try
                {
                    count = s.Receive(byteIn);
                }
                catch (Exception e6)
                {
                    Console.WriteLine(e6.Message);
                    Log.Push(LogItemType.Error, e6.Message);
                    return;
                }
                if (count > 0)
                {
                    OnNewMessage(new NewMessageEventArgs(byteIn, count));
                }
            }
        }
    }

此线程一旦创建就会永久工作。我只是想知道是否应该将此线程配置为在某个核心上运行?由于我需要最低延迟,我想避免上下文切换。因为我想避免上下文切换,我最好在同一处理器核心上运行相同的线程,对吗?

考虑到我需要最低延迟是正确的:

  • 最好为“长期运行”的线程设置“thread afinity”吗?
  • 最好从上面的例子中为线程设置“thread afinity”吗?

我现在将上面的代码重写为c ++以便稍后移植到Linux,如果这很重要,但我认为我的问题更多的是关于硬件而不是语言或操作系统。

3 个答案:

答案 0 :(得分:2)

我认为延迟尽可能小的算法是将线程固定到一个核心并将它们设置为实时优先级(或者是最高优先级)。

这将导致操作系统驱逐恰好使用该核心的任何其他线程。

希望当你的线程在那里安排时,CPU缓存仍然包含有用的数据。出于这个原因,我喜欢固定核心的想法。

您应该将整个过程设置为高优先级,并尽量减少盒子上的其他活动。还要关闭未使用的硬件,因为它可能会产生中断。将NIC的中断修复到不同的CPU核心(一些更好的NIC可以做到这一点)。

答案 1 :(得分:1)

  

由于我想避免上下文切换,我最好在同一处理器核心上运行相同的线程,对吗?

没有。通过设置与一个CPU的亲和性,不一定可以避免上下文切换。您无法控制上下文切换,它们掌握在OS线程调度程序中。它们发生在线程量子(时间片)已经过去或者更高优先级的线程中断了你的线程时。

你谈到的延迟,我假设是网络或内存延迟,通过设置线程关联性完全没有避免。通过使代码缓存友好(例如,它可以都在L1-L2缓存中)可以避免内存延迟。网络延迟实际上只是任何网络的一部分,而不是我怀疑你可以做很多事情。

答案 2 :(得分:0)

由于Tony The Lion已经回答了你的问题,我想谈谈你的评论:

  

“为什么不在我的代码中设置线程?为什么我的示例中的线程需要在核心之间移动?”

你的帖子不会去任何地方。

当OS线程调度程序决定给你的线程一段时间执行时,就会发生上下文切换。然后为您的线程准备环境,例如CPU注册 设置为正确的值等。这称为上下文切换。

因此,无论线程关联性如何,都必须完成相同的CPU设置工作,无论它是在线程运行时还是另一个切片中使用的前一个切片中使用的相同CPU /核心。此时,您的计算机有更多信息可以正确地完成,然后在编译时完成。

你似乎相信线程以某种方式驻留在CPU上,但事实并非如此。你使用的是一个逻辑线程,可能有数百甚至数千个。通用CPU OTOH通常每个内核有1或2个硬件线程,每次调度时,逻辑线程都会映射到其中一个,即使操作系统总是选择相同的HW线程。

编辑:您似乎已经选择了想要听到的答案,我不喜欢长时间讨论答案,所以我会把它放在这里。

  • 你应该尝试测量它。我相信你会失望的
  • 在高优先级线程上运行某些线程可能会轻易搞乱其他进程
  • 您担心上下文切换延迟,但您没有问题,GC线程会冻结您的线程吗? BTW,您的GC线程将在哪个核心运行? :)
  • 如果您的最高优先级线程阻止GC线程怎么办?内存泄漏?你知道那个帖子的优先级是什么,所以你确定它会起作用吗?
  • 真的,如果微秒很重要,为什么不用C或手动优化装配?
  • 正如有人建议的那样,如果你想控制这方面的执行,你应该使用RTOS
  • 您的数据通过数据中心传输的速度似乎不比在一台计算机上设置线程上下文慢4-5倍,但谁知道......