Nov*_*zky 7 c# performance multithreading ipc low-latency
控制台应用程序有3个线程:Main,T1,T2.目标是尽可能以最低延迟(μs)从主线程"发信号"T1,T2(并让它们做一些工作)
注意:
看看下面的代码:
样品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中得到的是我能达到的最好成绩吗?
有什么建议?
当我有时间时,我会尝试原始套接字.
没有太多可以做的事情,因为另一个线程必须由操作系统调度。
增加等待线程的优先级是唯一可能产生很大影响的事情,并且您已经这样做了。你还可以走得更高。
如果您确实需要尽可能低的延迟来激活另一个任务,则应该将其转换为可以直接从触发线程调用的函数。