关于确保在IAsyncResult对象列表上调用EndInvoke()的两个问题

时间:2010-06-14 11:45:00

标签: .net asynchronous iasyncresult

所以这个问题与。this问题

中提到的.Net IAsyncResult设计模式和调用EndInvoke的必要性有关。

背景

我有一些代码可以解决对特定函数的潜在许多异步调用,然后在使用EndInvoke()取回所有结果之前等待所有这些调用完成。

问题1

我不知道在调用EndInvoke()之前是否有任何调用遇到异常,并且如果在其中一个调用中发生异常,则整个方法应该失败并且异常被包装到API特定异常并向上抛出。

所以我的第一个问题是确保剩余的异步调用能够正确终止的最佳方法是什么?

finally块是否会在未终止的其余调用上调用EndInvoke()(并忽略任何进一步的异常),这是最好的方法吗?

问题2

其次,当我第一次触发所有的asyc调用时,然后在我WaitHandle.WaitAll()个实例的WaitHandle个实例数组上调用IAsyncResult。触发所有这些异步调用的方法有一个超时要遵守,因此我将此提供给WaitAll()方法。然后我测试是否所有调用都已完成,如果没有,则必须达到超时,因此该方法也应该失败并抛出另一个API特定的异常。

所以我的第二个问题是在这种情况下该怎么做?

我需要在抛出错误之前调用EndInvoke()来终止所有这些异步调用,但同时我不希望代码因EndInvoke()阻塞而卡住。理论上至少如果WaitAll()调用超时则所有异步调用本身都应该超时并抛出异常(从而完成调用),因为它们也受超时控制,但是这个超时可能与主要不同超时

2 个答案:

答案 0 :(得分:1)

我将遍历您的IAsyncResult个对象,将每个EndInvoke包装在try / catch中,以便在其他地方存储任何生成的异常。然后,当您调用所有EndInvoke时,您可以查看是否存储了任何异常并抛出API异常(如果是这样)。类似的东西:

var exs = new List<Exception>();

foreach (IAsyncResult iasr in asyncResults) {
    try {
        iasr.EndInvoke();
    }
    catch (Exception e) {
        exs.Add(e);
    }
}

if (exs.Count > 0) {
    throw new MyException(exs.ToReadOnly());
}

答案 1 :(得分:0)

如果可能的话,我建议使用Tasks而不是IAsyncResult。它们具有更好的“延续”语义,可以包装IAsyncResult API,为您调整EndInvoke。