2015-04-02 65 views
-2

我正在編寫一個與多個WCF終端進行通信的庫。在很多情況下,我必須等待遠程服務的特定狀態或條件。我寫了一個簡單的投票等待循環,看起來是這樣的:阻止輪詢等待循環執行的更好方法?

private bool WaitForTrue(Func<bool> action, TimeSpan waitTime, TimeSpan checkInterval) 
{ 
    DateTime end = DateTime.UtcNow + waitTime; 
    while (DateTime.UtcNow < end) 
    { 
     if (action()) 
     { 
      return true; 
     } 
     Thread.Sleep(checkInterval); 
    } 

    return action(); 
} 

閱讀severalpostsThread.Sleep是如何設計不良的節目的標誌後,我重新評估每一個我用它的地方。我正在努力用最好的方式來取代它在這個等待循環中的使用。我見過使用Task.Delay的建議,但由於我必須阻止執行,因此我認爲我將不得不使用Task.Delay(checkInterval).Wait(),這似乎並不能提供任務的典型優勢。

我知道使用基於回調/基​​於事件的WCF方法而不是輪詢的優點,但不幸的是,我無法修改服務端點來公開這種功能。

我的庫沒有使用任何多線程,但我希望它對希望多線程應用程序的消費者友好。

正在取代Thread.SleepTask.Delay.Wait()的路要走,還是有更好的方法來實現阻塞等待循環?

+0

爲什麼沒有計時器並在其事件上執行該功能? – Ewan 2015-04-02 16:04:20

+0

@Ewan我也看到了這個建議,但是我很難想象這會如何工作。你介意用一個例子發佈一個答案嗎? – 2015-04-02 16:46:31

+0

因此,您正在輪詢遠程服務,該服務無法通知您? – usr 2015-04-02 17:09:52

回答

1

由於當您正在查找的事件發生時您無法通過服務通知投票是最好的選擇。

如果您有很多這些輪詢循環同時運行,請考慮使用異步等待來釋放線程。這需要使用,例如,

await Task.Delay(...); 

並使輪詢方法和整個調用鏈異步。

如果只有幾個這樣的輪詢循環,這會浪費開發時間。

對於你在這裏所做的時間目的而言,睡覺是很好的。

1

您可以通過等待一個永不發送信號的互斥體來避免Thread.Sleep。例如,鉤住自己一個互斥和使用,需要一個時間跨度的WaitOne overloads之一

private bool WaitForTrue(
    Func<bool> action, TimeSpan waitTime, TimeSpan checkInterval) 
{ 
    using(var mutie = new Mutex()) 
    { 
     DateTime end = DateTime.UtcNow + waitTime; 
     while (DateTime.UtcNow < end) 
     { 
      if (action()) 
      { 
       return true; 
      } 
      mutie.WaitOne(checkInterval); 
     }  
     return action(); 
    } 
} 

我不相信這樣做實際上意味着你比那些更好的程序員使用了Thread.Sleep ...

(經過一點研究)看起來Task.Delay釋放當前線程,然後在(可能)不同的線程上稍後重新開始執行。這絕對比釋放線程更好(鎖定線程)。如果您在執行過程中已經使用任務,並且不需要需要來阻止當前線程,那麼Task.Delay或許是您最好的選擇。

+0

爲什麼不把它放到極限並使用Rx。創建主題以向訂戶廣播更改? – 2015-04-02 16:18:36

+0

@JohnTaylor Dunno。矯枉過正?你可以隨時添加一個答案。 – Will 2015-04-02 16:19:18

+0

我仍然在理解Rx的過程。 Rx和任務導致一些非常複雜的線程執行,但是它們可以刪除所有的等待和睡眠,這是完整的。 – 2015-04-02 16:25:15