等待事情发生 – 异步或同步模型?

我有这个方法WaitForReaderArrival ,如下所示:( 等待读者到达的所有时间运行)

  public void WaitForReaderArrival() { do { if (ReaderArrived()) { break; } System.Threading.Thread.Sleep(1000); } while (ReaderArrived() == false); } 

而我正在等待读者使用,

  await Task.Run(new Action(WaitForReaderArrival)); if (ReaderArrived()) { //Raise an ReaderArrived here! ..//blah blah } 

我的一位同事让我改变上面这句话

  WaitForReaderArrival(); if (ReaderArrived()) { //Raise an ReaderArrived here! ..//blah blah } 

问题是:

  1. 我上面采用的异步模型是不是真的有用? 为什么她要我将这一行更改为正常的同步方法仍然是一个问题。

  2. 以上是等待事情发生然后继续的正确方法?

我上面采用的异步模型是不是真的有用? 为什么她要我将这一行更改为正常的同步方法仍然是一个问题。

您正在使用的代码是繁忙等待循环的略微改进版本,它正在轮询具有限制的内容。 如果您没有任何其他方式获得更改通知 ,您可以将此循环卸载到池线程,因为您已经在await Task.Run ,或者更好的是,使用Task.Delay

 public async Task WaitForReaderArrivalAsync() { while (!ReaderArrived()) { await Task.Delay(1000).ConfigureAwait(false); } } 

我的一位同事让我改变了以上界限……以上是等待事情发生然后继续进行的正确方法?

你的同事错了。 如果你调用原来的WaitForReaderArrival而不用await Task.Run包装它,或者调用上面提出的版本作为WaitForReaderArrivalAsync().Wait() ,你将阻止UI线程。 要保持UI线程消息循环function,您应该使代码“始终异步” :

 // top-level event handler async void Button_Click(object sender, EventArgs e) { await WaitForReaderArrivalAsync(); MessageBox.Show("ReaderArrived!"); } 

这是调用它的正确方法。 从概念上讲,它与在计时器事件上检查ReaderArrived非常相似,但是async/await为您提供了方便的线性伪同步代码流。

注意,有一种流行的反模式 ,它忙于等待DoEvents以保持UI响应,有效地在UI线程上创建嵌套的消息循环:

 public void WaitForReaderArrival() { while (!ReaderArrived()) { Application.DoEvents(); System.Threading.Thread.Sleep(100); } } 

这样做是错误的: 保持您的UI响应和Application.DoEvents的危险 。

从您的代码的角度来看,没有区别。 执行将在此时停止,直到相关事件发生后才会恢复。

从其他并发活动的角度来看,它们不可能更加不同。 在’await’情况下,线程不会阻塞,在第二个同步情况下它会阻塞。 关于使用哪个因素的决定取决于您未在此处泄露的其他因素。

如果这是UI线程,您很可能不希望它阻止。 使用’await’。

如果这是一个专用的工作线程,您很可能希望它阻止。 使用同步表单。

我必须指出,在严格的分析中,第二个if (ReaderArrived())是错误的。 它应该是一个断言,因为否则没有什么有用的。

另外,考虑避免“忙碌的睡眠”等待。 做这种事通常是一种糟糕的方式。

最后,在来到这里之前,你必须先熟悉与同事交谈的想法。 🙂

回答你的第二点基本上我建议不要使用上面的代码使用事件,如果你的意图是在发生另一个事件时做的事情。

以上是等待事情发生然后继续的正确方法?

您可以将延续(也称为回调)传递给您的过程:

 public void WaitForReaderArrival(Action callback) { do { if ( ReaderArrived() ) { break; } System.Threading.Thread.Sleep(1000); } while ( ReaderArrived() == false ); callback(); } 

用法示例:

 WaitForReaderArrival(() => { // Raise an ReaderArrived here! // ...blah blah }); 

我上面采用的异步模型是不是真的有用? 为什么她要我将这一行更改为正常的同步方法仍然是一个问题。

关键是在你的应用程序的某个地方,你将不得不等待Reader到达。 即使你在另一个后台线程中等待,你仍然需要等待该线程完成。

我唯一关心的是在UI线程上使用Thread.Sleep()会冻结你的应用程序。 考虑基于事件的方法。