同一进程中线程之间的低延迟通信

Nov*_*zky 7 c# performance multithreading ipc low-latency

控制台应用程序有3个线程:Main,T1,T2.目标是尽可能以最低延迟(μs)从主线程"发信号"T1,T2(并让它们做一些工作)

注意:

  • 请忽略抖动,GC等(我可以处理)
  • ElapsedLogger.WriteLine通话费用低于50ns(纳秒)

看看下面的代码:

样品1

class Program
{
    private static string msg = string.Empty;
    private static readonly CountdownEvent Countdown = new CountdownEvent(1);

    static void Main(string[] args)
    {
        while (true)
        {
            Countdown.Reset(1);
            var t1 = new Thread(Dowork) { Priority = ThreadPriority.Highest };
            var t2 = new Thread(Dowork) { Priority = ThreadPriority.Highest };
            t1.Start();
            t2.Start();

            Console.WriteLine("Type message and press [enter] to start");
            msg = Console.ReadLine();

            ElapsedLogger.WriteLine("Kick off!");
            Countdown.Signal();

            Thread.Sleep(250);
            ElapsedLogger.FlushToConsole();
        }
    }
    private static void Dowork()
    {
        string t = Thread.CurrentThread.ManagedThreadId.ToString();
        ElapsedLogger.WriteLine("{0} - Waiting...", t);

        Countdown.Wait();

        ElapsedLogger.WriteLine("{0} - Message received: {1}", t, msg);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Type message and press [enter] to start
test3
20141028 12:03:24.230647|5 - Waiting...
20141028 12:03:24.230851|6 - Waiting...
20141028 12:03:30.640351|Kick off!
20141028 12:03:30.640392|5 - Message received: test3
20141028 12:03:30.640394|6 - Message received: test3

Type message and press [enter] to start
test4
20141028 12:03:30.891853|7 - Waiting...
20141028 12:03:30.892072|8 - Waiting...
20141028 12:03:42.024499|Kick off!
20141028 12:03:42.024538|7 - Message received: test4
20141028 12:03:42.024551|8 - Message received: test4
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,"延迟"大约是40-50μs.CountdownEvent信令调用非常便宜(小于50ns),但T1,T2线程被暂停,唤醒它们需要时间.

样本2

class Program
{
    private static string _msg = string.Empty;
    private static bool _signal = false;

    static void Main(string[] args)
    {
        while (true)
        {
            _signal = false;
            var t1 = new Thread(Dowork) {Priority = ThreadPriority.Highest};
            var t2 = new Thread(Dowork) {Priority = ThreadPriority.Highest};
            t1.Start();
            t2.Start();

            Console.WriteLine("Type message and press [enter] to start");
            _msg = Console.ReadLine();

            ElapsedLogger.WriteLine("Kick off!");
            _signal = true;

            Thread.Sleep(250);
            ElapsedLogger.FlushToConsole();
        }
    }
    private static void Dowork()
    {
        string t = Thread.CurrentThread.ManagedThreadId.ToString();
        ElapsedLogger.WriteLine("{0} - Waiting...", t);

        while (!_signal) { Thread.SpinWait(10); }

        ElapsedLogger.WriteLine("{0} - Message received: {1}", t, _msg);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Type message and press [enter] to start
testMsg
20141028 11:56:57.829870|5 - Waiting...
20141028 11:56:57.830121|6 - Waiting...
20141028 11:57:05.456075|Kick off!
20141028 11:57:05.456081|6 - Message received: testMsg
20141028 11:57:05.456081|5 - Message received: testMsg

Type message and press [enter] to start
testMsg2
20141028 11:57:05.707528|7 - Waiting...
20141028 11:57:05.707754|8 - Waiting...
20141028 11:57:57.535549|Kick off!
20141028 11:57:57.535576|7 - Message received: testMsg2
20141028 11:57:57.535576|8 - Message received: testMsg2
Run Code Online (Sandbox Code Playgroud)

此时"延迟"约为6-7μs.(但是CPU很高)这是因为T1,T2线程被强制激活(它们什么都不做只是烧掉CPU时间)

在'真正的'应用程序中,我不能像那样旋转CPU(我有很多活动线程,它会使它更糟/更慢甚至杀死服务器).

是否可以使用任何东西来降低10-15μs左右的延迟?我猜使用Producer/Consumer模式它不会比使用CountdownEvent更快.等待/脉冲也比CountdownEvent贵.

我在样本1中得到的是我能达到的最好成绩吗?

有什么建议?

当我有时间时,我会尝试原始套接字.

Ben*_*igt 1

没有太多可以做的事情,因为另一个线程必须由操作系统调度。

增加等待线程的优先级是唯一可能产生很大影响的事情,并且您已经这样做了。你还可以走得更高。

如果您确实需要尽可能低的延迟来激活另一个任务,则应该将其转换为可以直接从触发线程调用的函数。