4

在我的 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));
                }
            }
        }
    }

该线程一旦创建就永远有效。我只是想知道我是否应该将此线程配置为在某些核心上运行?由于我需要最低延迟,我想避免上下文切换。由于我想避免上下文切换,我最好在同一个处理器内核上运行同一个线程,对吧?

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

  • 为大部分“长时间运行”线程设置“线程亲和力”会更好吗?
  • 从上面的示例中为线程设置“线程亲和力”会更好吗?

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

4

3 回答 3

2

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

这将导致操作系统驱逐碰巧使用该内核的任何其他线程。

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

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

于 2013-03-08T14:17:13.833 回答
1

由于我想避免上下文切换,我最好在同一个处理器内核上运行同一个线程,对吧?

不会。将关联设置到一个 CPU 不一定可以避免上下文切换。您无法控制上下文切换,它们掌握在操作系统线程调度程序的手中。它们发生在线程量子(时间片)已经过去或更高优先级的线程中断您的线程时。

您所说的延迟,我认为是网络或内存延迟,根本无法通过设置线程亲和性来避免。内存延迟可以通过使您的代码缓存友好来避免(例如,它都可以在 L1 - L2 缓存中)。网络延迟实际上只是任何网络的一部分,而不是我怀疑您可以做很多事情的事情。

于 2013-03-08T13:52:35.940 回答
1

由于托尼狮子已经回答了你的问题,我想谈谈你的评论:

“为什么不对我的代码设置线程亲和性?为什么我的示例中的线程需要在内核之间传输?”

您的线程不会传播到任何地方。

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

因此,无论线程亲和性如何,都必须完成相同的 CPU 设置工作,无论是线程运行时在前一个切片中使用的 CPU/内核还是另一个。此时,您的计算机拥有比编译时更多的信息来正确执行此操作。

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

编辑:看来你已经选择了你想听到的答案,我不喜欢关于答案的长时间讨论线程,所以我会把它放在这里。

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