控制台应用程序有3个线程:主线程、T1线程和T2线程。
目标是在最低延迟(μs)内“信号”T1、T2线程并让它们执行一些工作。
注意:
- 请忽略Jitter、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);
}
}
输出:
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
在上面的代码中,'延迟'大约为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);
}
}
输出:
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
这次的'延迟'大约是6-7微秒。(但CPU占用率很高)这是因为T1、T2线程被强制活跃(它们什么也不做,只是消耗CPU时间)
在“真实”的应用程序中,我不能像那样旋转CPU(我有太多的活动线程,这会使它变得更糟/更慢甚至导致服务器崩溃)。
是否有其他方法可以将延迟降低到大约10-15微秒?我猜使用生产者/消费者模式不会比使用CountdownEvent更快。等待/脉冲比CountdownEvent更昂贵。
在示例1中我得到的是最好的结果吗?
有什么建议吗?
我有时间时也会尝试使用原始套接字。
ManualResetEventSlim
和SemaphoreSlim
吗?Monitor.Wait
和Monitor.Pulse
呢? - Jim Mischel