等待带有回调的多个方法完成
Wait for multiple methods with callbacks to finish
我有多个异步方法需要调用并等待它们全部完成。异步方法都具有在异步处理完成时执行的回调参数。所以我想我需要在每个回调中放置一些信号设备,然后等待所有信号到来后再继续。
搜索后,我想我可以使用 AutoResetEvents
的数组,然后调用 WaitHandle.WaitAll
来等待它们。类似于:
WaitHandle[] waitHandles = new WaitHandle[]
{
new AutoResetEvent(false),
new AutoResetEvent(false)
};
DoWorkA((callback) =>
{
waitHandles[0].Set();
});
DoWorkB((callback) =>
{
waitHandles[1].Set();
});
// wait for DoWorkA and DoWorkB to finish
WaitHandles.WaitAll(waitHandles);
// continue with the processing
我想知道这是否是一个好方法,或者是否有 better/simpler 方法。我需要 .Net 2.0 的解决方案,但我也想知道更高版本的 .Net 可以使用哪些其他解决方案。
编辑:
尝试此代码后,我发现它不起作用。 UI 线程在 WaitHandles.WaitAll(waitHandles)
处停止并且回调从不 运行...
在 DoWork 方法中有代码在后台线程上 运行 asnychronously,然后我尝试从那个后台线程 运行 通过 BeginInvoke
在控件上调用的回调来自 UI 线程。但是,回调永远不会在 UI 线程上执行。知道我做错了什么吗?
编辑 2:
我意识到它为什么不起作用 - 调用 WaitHandles.WaitAll(waitHandles)
的线程与回调尝试 运行 的线程相同(UI 线程)。所以当然,如果线程正在等待信号,回调将永远不会在同一个线程上 运行,因此永远不会调用 Set()
。 WaitAll(waitHandles) 和 Set() 应该可以工作,只要它们不是 运行 在同一个线程上。我想我需要修复它,以便在 UI 线程等待时后台线程上的回调 运行。如果我的想法不正确,请告诉我。
是的,使用事件是等待多个回调完成的合理方式,对于 2.0,如果您不能使用外部库,这可能是您可以做的最好的事情。
你可以用一个事件和计数回调完成来重写代码,但它可能更复杂(同时允许无限数量的回调)。或者可以通过 Semaphore.
实现类似的方法
如果你可以使用 4.5+,而不是用 async
/await
重写方法可能是更好的选择。
// use "async Task(...)" as equivalent of "void DoWorkA(...)".
async Task<int> DoWorkAAsync(int arg1)
{
var serviceResult = await service.CallAsync(arg1);
return ParseServiceResult(serviceResult);
}
async Task<int> DoWorkBAsync()
{
... await SomeAsync(1,2,3);...
return someResult;
}
var tasks = new[] {DoWorkAAsync(42), DoWorkBAsync() };
await Task.WhenAll(tasks);
var resultOfA = tasks[0].Result;
我有多个异步方法需要调用并等待它们全部完成。异步方法都具有在异步处理完成时执行的回调参数。所以我想我需要在每个回调中放置一些信号设备,然后等待所有信号到来后再继续。
搜索后,我想我可以使用 AutoResetEvents
的数组,然后调用 WaitHandle.WaitAll
来等待它们。类似于:
WaitHandle[] waitHandles = new WaitHandle[]
{
new AutoResetEvent(false),
new AutoResetEvent(false)
};
DoWorkA((callback) =>
{
waitHandles[0].Set();
});
DoWorkB((callback) =>
{
waitHandles[1].Set();
});
// wait for DoWorkA and DoWorkB to finish
WaitHandles.WaitAll(waitHandles);
// continue with the processing
我想知道这是否是一个好方法,或者是否有 better/simpler 方法。我需要 .Net 2.0 的解决方案,但我也想知道更高版本的 .Net 可以使用哪些其他解决方案。
编辑:
尝试此代码后,我发现它不起作用。 UI 线程在 WaitHandles.WaitAll(waitHandles)
处停止并且回调从不 运行...
在 DoWork 方法中有代码在后台线程上 运行 asnychronously,然后我尝试从那个后台线程 运行 通过 BeginInvoke
在控件上调用的回调来自 UI 线程。但是,回调永远不会在 UI 线程上执行。知道我做错了什么吗?
编辑 2:
我意识到它为什么不起作用 - 调用 WaitHandles.WaitAll(waitHandles)
的线程与回调尝试 运行 的线程相同(UI 线程)。所以当然,如果线程正在等待信号,回调将永远不会在同一个线程上 运行,因此永远不会调用 Set()
。 WaitAll(waitHandles) 和 Set() 应该可以工作,只要它们不是 运行 在同一个线程上。我想我需要修复它,以便在 UI 线程等待时后台线程上的回调 运行。如果我的想法不正确,请告诉我。
是的,使用事件是等待多个回调完成的合理方式,对于 2.0,如果您不能使用外部库,这可能是您可以做的最好的事情。
你可以用一个事件和计数回调完成来重写代码,但它可能更复杂(同时允许无限数量的回调)。或者可以通过 Semaphore.
实现类似的方法如果你可以使用 4.5+,而不是用 async
/await
重写方法可能是更好的选择。
// use "async Task(...)" as equivalent of "void DoWorkA(...)".
async Task<int> DoWorkAAsync(int arg1)
{
var serviceResult = await service.CallAsync(arg1);
return ParseServiceResult(serviceResult);
}
async Task<int> DoWorkBAsync()
{
... await SomeAsync(1,2,3);...
return someResult;
}
var tasks = new[] {DoWorkAAsync(42), DoWorkBAsync() };
await Task.WhenAll(tasks);
var resultOfA = tasks[0].Result;