等待任何异步方法和(事件或布尔值)
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;
}
基本上它会等待两个事件中的任何一个:
- 如果收到请求,它会处理它并等待下一个请求。
- 如果引发 EventListenerStopped,它会退出循环。
这段代码已经 运行 漂亮地投入生产了一段时间了。
我想尝试将其转换为新的 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
。
我有这个代码:
ManualResetEvent EventListenerStopped;
...
while (true)
{
IAsyncResult iar = this.ListenerHttp.BeginGetContext(ProcessRequest, null);
if (WaitHandle.WaitAny(new[] { this.EventListenerStopped, iar.AsyncWaitHandle }) == 0)
return;
}
基本上它会等待两个事件中的任何一个:
- 如果收到请求,它会处理它并等待下一个请求。
- 如果引发 EventListenerStopped,它会退出循环。
这段代码已经 运行 漂亮地投入生产了一段时间了。
我想尝试将其转换为新的 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
。