2015-04-02 102 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