如何连接异步枚举?

时间:2015-02-23 16:10:57

标签: c# asynchronous async-await task-parallel-library ienumerable

我有一个返回类型的方法:

public async Task<IEnumerable<T>> GetAll()

它进行了一些进一步的异步调用(未知数),每个调用返回一个可枚举T的任务,然后想要连接返回的结果。

var data1 = src1.GetAll();
var data2 = src2.GetAll();
var data3 = src3.GetAll(); //and so on

现在很容易等待所有并连接结果以产生单个可枚举,但我希望第一次调用返回时可枚举可用,如果有任何调用,可能会等待调用者/枚举器当可用结果用完时仍然悬而未决。

我是否必须手动滚动一个concat来解决这个问题,当它包含在一个任务中时,缺少枚举器支持&lt;&gt;?或者在TPL或其他地方已经有一个图书馆电话可以帮助我。我确实看过IX,但它仍处于试验版本,并且不想折叠它。

另一方面,我正在尝试反模式吗?我可以想到一个复杂的,异常处理 - 从呼叫者的角度来看,呼叫可以成功完成并且他开始使用可枚举的但是它可以在中途爆炸......

1 个答案:

答案 0 :(得分:6)

现有一个名为Async Enumerable的项目可以完全解决这个问题。

你可以很容易地使用它。

例如:

IAsyncEnumerable<string> GetAsyncAnswers()
{
    return AsyncEnum.Enumerate<string>(async consumer =>
    {
        foreach (var question in GetQuestions())
        {
            string theAnswer = await answeringService.GetAnswer(question);
            await consumer.YieldAsync(theAnswer);
        }
    });
}

这会暴露IAsyncEnumerable<string>,一旦GetAnswer返回就会产生。您可以在内部公开IAsyncEnumerable<T>,并在GetAll内部进行调用。

  

我在尝试一种反模式?我能想到一个并发症,   异常处理 - 从呼叫方那边,呼叫可以完成   成功,他开始使用可枚举,但它可以爆炸   中途... ...

我不会这么说。这确实存在潜在问题,例如在其中一个等待期间内部发生异常,但这也可能可能发生在任何IEnumerable<T>内。异步序列是当今新兴异步API的现实所需要的。