嵌套的异步lambda没有等待

时间:2015-07-23 11:16:23

标签: c# mongodb lambda async-await

以下代码不会返回它正在迭代的整个集合。返回的数组在每次运行时都有任意长度。怎么了?

public async Task Iterate(Action<TDocument> processor)
{
    await _collection.Find<TDocument>(_ => true).ForEachAsync(processor);
}

以下代码使用新的异步MongoDB C#驱动程序

{{1}}

2 个答案:

答案 0 :(得分:4)

您看到任意数量的值的原因是Iterate收到类型为Action<T>的委托,相当于async void,这实际上使其成为“火” - 忘记“执行方式。

内部方法实际上并不知道异步委托已经传递给它,因此它迭代集合而不实际异步地等待每个项目完成。

您需要做的是将方法参数设为Func<TDocument, Task> and use the proper overload of ForEachAsync类型的委托:

public Task Iterate(Func<TDocument, Task> processor)
{
    return _collection.Find<TDocument>(_ => true).ForEachAsync(processor);
}

您可以看到source here

public static async Task ForEachAsync<TDocument>(
                    this IAsyncCursor<TDocument> source, 
                    Func<TDocument, int, Task> processor,
                    CancellationToken cancellationToken = default(CancellationToken))
{
    Ensure.IsNotNull(source, "source");
    Ensure.IsNotNull(processor, "processor");

    // yes, we are taking ownership... assumption being that they've
    // exhausted the thing and don't need it anymore.
    using (source)
    {
        var index = 0;
        while (await source.MoveNextAsync(cancellationToken).ConfigureAwait(false))
        {
            foreach (var document in source.Current)
            {
                await processor(document, index++).ConfigureAwait(false);
                cancellationToken.ThrowIfCancellationRequested();
            }
        }
    }
}

答案 1 :(得分:0)

您创建线程并将其设置为关闭。从那里你无法知道会发生什么。但是你的代码下一步是返回,所以你赌博线程将比你的主线程更快地执行。

在正常线程场景中,您将加入正在向包中添加项目的线程。连接是线程,等待其他线程执行,从而仍然是异步,但等待一切都完成之前返回。

这里有一个完美的解释:http://www.dotnetperls.com/thread-join