【问题标题】:Nested async lambda not awaited未等待嵌套的异步 lambda
【发布时间】:2018-05-06 11:40:01
【问题描述】:

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

public async Task<IHttpActionResult> GetClients()
{
    var clientInfoCollection = new ConcurrentBag<ClientInfoModel>();

    await _client.Iterate(async (client) =>
    {
        clientInfoCollection.Add(new ClientInfoModel
        {
            name = client.name,
            userCount = await _user.Count(clientId)
        });
    });

    return Ok(clientInfoCollection.ToArray());
}

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

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

【问题讨论】:

  • Iterate 是如何定义的?

标签: c# mongodb lambda async-await


【解决方案1】:

您看到任意数量的值的原因是,Iterate 接收类型为 Action&lt;T&gt; 的委托,相当于 async void,有效地使其成为“即发即弃”的风格执行。

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

您需要做的是让方法参数成为Func&lt;TDocument, Task&gt; 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();
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    您创建线程,然后将它们关闭。从那里你无法知道会发生什么。但是你的代码下一步是返回,所以你在赌线程会比你的主线程执行得更快。

    在正常的线程场景中,您将加入线程,他们正在将物品添加到包中。连接是线程,等待其他线程执行,因此仍然是异步的,但在一切完成之前等待返回。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-04
      • 2018-06-25
      • 2020-10-17
      • 2012-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多