在轮询等待循环中阻止执行的更好方法?
Better ways to block execution in polling wait loop?
我正在编写一个与多个 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();
}
阅读 several posts 关于 Thread.Sleep
是程序设计不佳的标志后,我正在重新评估我用过的每个地方。我正在努力寻找替换其在此等待循环中使用的最佳方法。我已经看到使用 Task.Delay
的建议,但由于我必须阻止执行,我认为我必须使用 Task.Delay(checkInterval).Wait()
,它似乎无法提供任务的典型优势。
我知道使用 callback/event-based WCF 方法而不是轮询的优点,但遗憾的是我无法修改服务端点以公开此类功能。
我的库不使用任何多线程,但我希望它对可能希望多线程应用程序的消费者友好。
用 Task.Delay.Wait()
替换 Thread.Sleep
是可行的方法,还是有更好的方法来实现阻塞等待循环?
您可以通过等待永远不会收到信号的互斥锁来避免 Thread.Sleep
。例如,给自己一个 Mutex 并使用需要时间跨度
的 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
是您最好的选择。
由于当您要查找的事件发生时服务无法通知您,轮询是您能做的最好的事情。
如果您同时有很多这样的轮询循环运行,请考虑使用异步等待来释放线程。这需要使用,例如,
await Task.Delay(...);
并使轮询方法和整个调用链异步。
如果只有几个这样的轮询循环,这是在浪费开发时间。
就你在这里做的时间而言,睡觉很好。
我正在编写一个与多个 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();
}
阅读 several posts 关于 Thread.Sleep
是程序设计不佳的标志后,我正在重新评估我用过的每个地方。我正在努力寻找替换其在此等待循环中使用的最佳方法。我已经看到使用 Task.Delay
的建议,但由于我必须阻止执行,我认为我必须使用 Task.Delay(checkInterval).Wait()
,它似乎无法提供任务的典型优势。
我知道使用 callback/event-based WCF 方法而不是轮询的优点,但遗憾的是我无法修改服务端点以公开此类功能。
我的库不使用任何多线程,但我希望它对可能希望多线程应用程序的消费者友好。
用 Task.Delay.Wait()
替换 Thread.Sleep
是可行的方法,还是有更好的方法来实现阻塞等待循环?
您可以通过等待永远不会收到信号的互斥锁来避免 Thread.Sleep
。例如,给自己一个 Mutex 并使用需要时间跨度
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
是您最好的选择。
由于当您要查找的事件发生时服务无法通知您,轮询是您能做的最好的事情。
如果您同时有很多这样的轮询循环运行,请考虑使用异步等待来释放线程。这需要使用,例如,
await Task.Delay(...);
并使轮询方法和整个调用链异步。
如果只有几个这样的轮询循环,这是在浪费开发时间。
就你在这里做的时间而言,睡觉很好。