等待任何异步方法和(事件或布尔值)

await any async method and (event or boolean)

我有这个代码:

ManualResetEvent EventListenerStopped;
...
while (true)
{
    IAsyncResult iar = this.ListenerHttp.BeginGetContext(ProcessRequest, null);
    if (WaitHandle.WaitAny(new[] { this.EventListenerStopped, iar.AsyncWaitHandle }) == 0)
        return;
}

基本上它会等待两个事件中的任何一个:

这段代码已经 运行 漂亮地投入生产了一段时间了。

我想尝试将其转换为新的 await/async 机制,但似乎找不到一个好的简单方法。

我尝试使用一个布尔值,调用者可以将其变为 false。它显然不起作用,因为它仅在收到并处理了新请求后才退出循环:

bool RunLoop;
...
while (this.RunLoop)
{
    HttpListenerContext listenerContext = await this.ListenerHttp.GetContextAsync();
    ProcessRequest(listenerContext);
}

我想知道是否有可能用 async/await 重写我简单的旧式循环。如果是,有人愿意告诉我怎么做吗?

它不特定于 async-await,但您可能正在寻找 CancellationToken(它与很多 async-await 代码一起使用):

http://blogs.msdn.com/b/pfxteam/archive/2009/05/22/9635790.aspx

'BlockingOperation' 示例代码似乎与您要执行的操作类似:

void BlockingOperation(CancellationToken token) 
{ 
   ManualResetEvent mre = new ManualResetEvent(false); 
   //register a callback that will set the MRE 
   CancellationTokenRegistration registration = 
      token.Register(() => mre.Set()); 
   using (registration) 
   { 
      mre.WaitOne(); 
      if (token.IsCancellationRequested) //did cancellation wake us? 
          throw new OperationCanceledException(token); 
   } //dispose the registration, which performs the deregisteration. 
}

嗯,首先我必须指出旧代码不太正确。在处理 Begin/End pattern 时,您 必须 始终调用 End,即使您想要(或确实)取消操作。 End常用来处置资源

如果您确实想使用取消,CancellationToken 可能是最好的方法:

while (true)
{
  // Throws an OperationCanceledException when cancellationToken is canceled.
  var request = await this.ListenerHttp.GetContextAsync(cancellationToken);
  ProcessRequest(request);
}

有替代方案 - 可能 做类似 Task.WhenAny 的事情,甚至有 AsyncManualResetEvent 的实现,因此可以创建几乎line-by-line 相当于旧代码,但 IMO 取消令牌方法会更清晰。

例如,使用AsyncManualResetEvent from my AsyncEx library:

AsyncManualResetEvent eventListenerStopped;
while (true)
{
  var task = GetContextAndProcessRequestAsync();
  if (await Task.WhenAny(eventListenerStopped.WaitAsync(), task) != task)
    return;
}

async Task GetContextAndProcessRequestAsync()
{
  var request = await this.ListenerHttp.GetContextAsync();
  ProcessRequest(request);
}

但就我个人而言,我会改为使用 CancellationToken