我有这个方法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
}
问题是:
我上面采用的异步模型是不是真的有用?为什么她要我将这一行更改为正常的同步方法仍然是一个问题。
以上是等待事情发生然后继续的正确方法?
答案 0 :(得分:5)
我上面采用的异步模型是不是真的有用? 她为什么要我将这一行改为普通的同步方法 对我来说仍然是一个问题。
您正在使用的代码是the busy waiting loop的稍微改进版本,它会对具有限制功能的内容进行轮询。 如果您没有任何其他方式获得更改通知,您可以将此循环卸载到池线程,就像您已经使用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线程消息循环的功能,您应该创建代码"Async All the Way":
// 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);
}
}
这样做是错误的:Keeping your UI Responsive and the Dangers of Application.DoEvents。
答案 1 :(得分:2)
从您的代码的角度来看,没有区别。执行将在此时停止,直到相关事件发生后才会恢复。
从其他并发活动的角度来看,它们之间的差别不大。在'await'情况下,线程不会阻塞,在第二个同步情况下它会阻塞。关于使用哪个因素的决定取决于您未在此处泄露的其他因素。
如果这是UI线程,您很可能不希望它阻止。使用'await'。
如果这是一个专用的工作线程,你很可能做希望它阻止。使用同步表单。
我必须指出,在严格的分析中,第二个if (ReaderArrived())
是错误的。它应该是一个断言,因为否则没有什么有用的。
另外,请考虑避免“忙碌的睡眠”等待。这通常是做这种事情的坏方法。
最后,你真的必须习惯于在来到这里之前先与同事交谈。 :)
答案 2 :(得分:0)
回答你的第二点 基本上我建议不要使用上面的代码使用事件,如果你的意图是在发生另一个事件时做的事情。
答案 3 :(得分:0)
以上是等待事情发生的正确方法 然后继续?
您可以将延续(a.k.a.回调)传递给您的程序:
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()
会冻结您的应用程序。考虑一种基于事件的方法。