等待事情发生 – 异步或同步模型?
我有这个方法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 }
问题是:
-
我上面采用的异步模型是不是真的有用? 为什么她要我将这一行更改为正常的同步方法仍然是一个问题。
-
以上是等待事情发生然后继续的正确方法?
我上面采用的异步模型是不是真的有用? 为什么她要我将这一行更改为正常的同步方法仍然是一个问题。
您正在使用的代码是繁忙等待循环的略微改进版本,它正在轮询具有限制的内容。 如果您没有任何其他方式获得更改通知 ,您可以将此循环卸载到池线程,因为您已经在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()
会冻结你的应用程序。 考虑基于事件的方法。