0

所以这个问题是关于 .Net IAsyncResult 设计模式和调用的必要性,EndInvoke问题所述

背景

我有一些代码,我可能会触发对特定函数的许多异步调用,然后等待所有这些调用完成,然后再使用EndInvoke()来取回所有结果。

问题 1

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

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

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

问题2

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

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

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

4

2 回答 2

1

我将遍历您的IAsyncResult对象,将每个对象包装EndInvoke在一个 try/catch 中,该 try/catch 将任何生成的异常存储在其他地方。然后,当您调用所有EndInvokes 时,您可以查看是否存储了任何异常,如果是,则抛出 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());
}
于 2010-06-14T11:48:45.740 回答
0

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

于 2010-06-14T13:27:41.203 回答