The console application has 3 threads: Main, T1, T2. The goal is to “signal” as T1, T2 (and let them do some work) from the main thread in the least delay as possible (μs)
NOTE.
- Please ignore Jitter, GC, etc. (I can handle this)
- Call Cost ElapsedLogger.WriteLine below 50 ns (nano sec)
Take a look at the code below:
sample 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); } }
Output:
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
In the above "latency" code is about 40-50 μs. The CountdownEvent callback is very cheap (less than 50 ns), but the T1, T2 streams are paused and it takes time to wake them up.
sample 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); } }
Output:
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
This time, "latency" is about 6-7 μs. (but high CPU) This is due to the fact that threads T1, T2 are forcibly activated (they do nothing, just record the processor time)
In a "real" application, I can’t rotate the processor like that (I have many active threads, and this will make it worse / slower or even kill the server).
Can I use something that I can use to drop latency by about 10-15 microseconds? I think that with the Producer / Consumer template it will not work faster than with the CountdownEvent. Wait / Pulse is also more expensive than CountdownEvent.
What I got in example 1, how much can I achieve?
Any suggestions?
I will also try raw sockets when I have time.