2014-02-10 28 views
3

我有这个方法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. 以上是什么等待事件发生并继续进行的正确方法?

+0

很可能应该有某种外部事件,发生在“读者到达”时,如用户输入,套接字消息,传入串行端口数据等。有没有类似的东西? – Noseratio

+0

不是。我正在编写的库公开了这个事件,并在上面的代码被击中时引发。 –

+2

您使用的代码是稍微改进的[busy waiting loop](http://en.wikipedia.org/wiki/Busy_waiting)版本,它用于调节某些内容。 **如果您没有任何其他方式获得更改**的通知,那么使用'await Task.Run'将这样的循环卸载到池线程可能是您可以做的最好的事情。 – Noseratio

回答

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

+0

可能有问题的代码没有在UI线程上运行。 – svick

+0

@svick,OP已经阐明了它是一个UI线程,但在非UI线程的情况下,我仍然坚持'等待Task.Delay(1000)',除非轮询间隔必须非常小。 – Noseratio

0

回答你的第二点 基本上我会建议不要用上面的代码去使用的事件,如果你的内涵是做一些事情上的另一个事件的occurence。

2

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

从其他同时活动的角度来看,它们不可能有更多不同。在'await'情况下,线程不会阻塞,在第二个同步情况下它会阻塞。关于使用哪一个的决定取决于您在此未披露的其他因素。

如果这是UI线程,您很可能不希望它阻塞。使用'等待'。

如果这是一个专门的工作线程,最有可能的是希望它阻止。使用同步形式。

我必须指出,在严格的分析中,第二个if (ReaderArrived())是错误的。这应该是一个断言,因为没有任何其他有用的做法。

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

最后,你真的必须习惯于在来到这里之前先与同事交谈。 :)

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()会冻结您的应用程序。考虑一种基于事件的方法。

+0

当你使用'await'时使用continuations通常是一个坏主意。 “await”使代码更清晰,更易于理解。 – svick

+0

是的,但是你仍然在使用“任务”。他的任务(双关意图)是将代码转换为普通的同步代码。我提出的解决方案基本上是一个事件模式,但没有使用C#事件。 –