2014-10-29 11 views
6

Ứng dụng bàn điều khiển có 3 luồng: Main, T1, T2. Mục đích là để 'tín hiệu' cả T1, T2 (và để cho họ làm một số công việc) từ các chủ đề chính trong độ trễ thấp nhất càng tốt (ms)Độ trễ thấp giữa các luồng trong cùng một quá trình

LƯU Ý:

  • xin vui lòng bỏ qua Jitter , GC vv (tôi có thể xử lý đó)
  • chi phí cuộc gọi ElapsedLogger.WriteLine dưới 50ns (nano giây)

Hãy nhìn vào mã bên dưới:

012.

mẫu 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 

Trong mã 'trễ' ở trên là khoảng 40-50μs. Cuộc gọi báo hiệu CountdownEvent rất rẻ (dưới 50ns) nhưng các luồng T1, T2 bị treo và phải mất thời gian để đánh thức chúng.

mẫu 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 

này thời gian 'trễ' là khoảng 6-7μs. (nhưng CPU cao) Điều này là do T1, T2 chủ đề được buộc phải hoạt động (họ không làm gì chỉ cần ghi thời gian CPU)

Trong ứng dụng 'thực' tôi không thể quay CPU như vậy (Tôi có nhiều chủ đề đang hoạt động và nó sẽ làm cho nó tồi tệ hơn/chậm hơn hoặc thậm chí giết chết máy chủ).

Có bất kỳ thứ gì tôi có thể sử dụng thay vào đó để giảm độ trễ xuống khoảng 10-15 μ? Tôi đoán với nhà sản xuất/mẫu người tiêu dùng nó sẽ không thực hiện nhanh hơn sử dụng CountdownEvent. Chờ/Pulse cũng đắt hơn CountdownEvent.

Tôi có thể đạt được điều gì trong mẫu 1 hay nhất?

Mọi đề xuất?

Tôi cũng sẽ thử các ổ cắm thô khi có thời gian.

+0

Bạn đã điều tra 'ManualResetEventSlim' và' SemaphoreSlim' chưa? Điều gì về 'Monitor.Wait' và' Monitor.Pulse'? –

+0

@JimMischel: Tôi đã thử tất cả chúng và kết quả là khá giống nhau. – Novitzky

Trả lời

1

Tôi đồng ý rằng phương pháp SpinWait() không thực tế để sử dụng sản xuất. Chủ đề của bạn sẽ phải đi ngủ và được đánh thức.

Tôi thấy bạn đã xem chờ/Xung. Bạn đã điểm chuẩn bất kỳ nguyên thủy nào khác có sẵn trong .net? "Threading in C#" của Joe Albahari có đánh giá toàn diện về tất cả các tùy chọn của bạn. http://www.albahari.com/threading/part4.aspx#_Signaling_with_Wait_and_Pulse

Một điểm tôi muốn chạm vào: Bạn tự tin vào dấu thời gian do ElapsedLogger tạo ra như thế nào?

+0

Cảm ơn bạn đã liên kết - Tôi biết 'Threading in C#' của anh ấy rất tốt. Tôi đã thử benchmarking rất nhiều thứ khác, luôn luôn sử dụng các thiết lập tương tự (phần cứng/OS/tối ưu hóa/GC/jitter/etc). Tín hiệu WaitAndPulse cho tôi độ trễ tương tự như CountdownEvent. Cuộc gọi Monitor.PulseAll() đắt hơn CountdownEvent.Signal() nhưng cả hai dưới 100-150ns. Về ElapsedLogger, độ phân giải là cách dưới 1us và tôi khá chắc chắn về điều đó. – Novitzky

1

Không có nhiều thứ có thể thực hiện được vì chuỗi khác phải được hệ điều hành lên lịch.

Tăng mức độ ưu tiên của chuỗi chờ đợi là điều duy nhất có thể tạo ra sự khác biệt nhiều và bạn đã thực hiện điều đó. Bạn có thể đi cao hơn nữa.

Nếu bạn thực sự cần độ trễ thấp nhất có thể để kích hoạt tác vụ khác, bạn nên biến nó thành một hàm có thể được gọi trực tiếp từ chuỗi kích hoạt.

+0

Ben, cảm ơn câu trả lời. Hai câu hỏi: 1) Làm thế nào tôi có thể đi thậm chí cao hơn với ưu tiên thread? Chủ đề cao nhất được lên lịch trước các chủ đề với bất kỳ ưu tiên nào khác. 2) Nếu tôi thực hiện một chức năng trực tiếp từ các chủ đề gọi điện thoại sẽ không có đa luồng ở tất cả. Sau đó, tôi sẽ thực hiện tác vụ một lần thay vì song song. Bạn có đề xuất chức năng này đá một thread khác thay thế? Tôi đã thử điều này và tôi không thể thấy bất kỳ cải tiến nào. – Novitzky

+0

1) Bạn đã sử dụng "Mức độ ưu tiên cao nhất" không cao bằng THREAD_PRIORITY_TIME_CRITICAL. 2) Bạn có ba hành động diễn ra ngay bây giờ - đánh thức hai chủ đề và tiếp tục chức năng hiện tại. Cho dù một trong ba nhiệm vụ mà ba luồng này chịu trách nhiệm là độ trễ quan trọng nhất nên được thực hiện trên luồng hiện tại. –

+0

Cảm ơn bạn đã THREAD_PRIORITY_TIME_CRITICAL. Tôi sẽ chơi với nó. Về điểm 2, trong ứng dụng thực tế tôi có từ 1 đến 8 chủ đề được độ trễ quan trọng (tất cả cần phải được kích hoạt bởi chủ đề khác). – Novitzky

Các vấn đề liên quan