【问题标题】:Why doesn't my function await the end of foreachAsync?为什么我的函数不等待 foreachAsync 结束?
【发布时间】:2019-07-25 15:02:41
【问题描述】:

我正在尝试使用从异步操作获取到数据库的数据来填充我的模型。问题是该函数返回视图(没有完成的模型),尽管我的 await 调用。

我尝试设置一个计时器(我知道这不是解决方案),以确保问题来自异步,我还尝试在我的 foreachAsync 中对部分代码进行注释,但它没有似乎没有帮助。

我得到一个项目列表,我填写了一些附加信息,最后,我将我的对象分配给我的模型,然后返回视图

public async Task<IActionResult> newProjetList(int GestionaireId, int VilleId)
        {
            ProjetListModel model = new ProjetListModel();
            ProjetService projetService = new ProjetService(connectionString);
            UserServices userServices = new UserServices(connectionString);
            AvancementService avancementService = new AvancementService(connectionString);
            VilleService villeService = new VilleService(connectionString);
            List<Projet> projets = await projetService.NewProjetLine(GestionaireId, VilleId);

            await projets.ToAsyncEnumerable().ForEachAsync(async p =>
            {
                int villeId = await villeService.getVilleIdByProjetId(p.ProjetId);
                Ville ville = await villeService.GetById(villeId);
                p.Ville = ville.VilleLabel;
                p.GestionnaireProjet = await userServices.GetNameById(p.GestionnaireProjetId ?? 0);
                await p.SousProjet.ToAsyncEnumerable().ForEachAsync(async sp =>
                 {
                     sp.Avancement = await avancementService.GetLabelById(sp.AvancementId);
                 });
            });
            model.projets = projets;
            //System.Threading.Thread.Sleep(5000);
            return View("ProjetList", model);
        }

我希望输出缺少信息(这里是“ville”、“gestionnairesProjet”和“Avancement”

【问题讨论】:

  • 我可以问一个问题:为什么你在做.ToAsyncEnumerable().ForEachAsync?这似乎是一种非常低效foreach(var project in projects) {...} 方式?它没有添加任何我能看到的东西......
  • @MarcGravell 这让事情变得更糟,因为循环有一个await 来获取下一个项目。我认为 OP 误解了 ForEachAsync 的作用。它不允许您聚合一堆任务。相反,它允许您遍历异步集合(您必须在其中使用 await iterator.MoveNext()。)如下面的答案所述,OP 真正想要的是 Task.WhenAll
  • @RaymondChen 每个项目的等待并不可怕 - 这是一个在这种情况下已经完成的价值任务。没有增加重大开销。

标签: c# linq asynchronous .net-core


【解决方案1】:

ForEachAsync 只接受Action&lt;...&gt;,而不是Func&lt;..., Task&gt;,因此您的代码传递给ForEachAsyncasync lambda 正在变成async void method。应该避免使用async void 的主要原因之一是,确定方法何时完成并不容易——事实上,在这种情况下,没有什么可以确保它在发送响应之前完成。

我建议按照 Marc 的建议做,只使用 foreach

List<Projet> projets = await projetService.NewProjetLine(GestionaireId, VilleId);

foreach (var p in projects)
{
  int villeId = await villeService.getVilleIdByProjetId(p.ProjetId);
  Ville ville = await villeService.GetById(villeId);
  p.Ville = ville.VilleLabel;
  p.GestionnaireProjet = await userServices.GetNameById(p.GestionnaireProjetId ?? 0);
  foreach (var sp in p.SousProject)
  {
    sp.Avancement = await avancementService.GetLabelById(sp.AvancementId);
  }
}
model.projets = projets;

或者,如果你想使用异步并发,你可以使用Task.WhenAll

List<Projet> projets = await projetService.NewProjetLine(GestionaireId, VilleId);

await Task.WhenAll(projects.Select(async p =>
{
  int villeId = await villeService.getVilleIdByProjetId(p.ProjetId);
  Ville ville = await villeService.GetById(villeId);
  p.Ville = ville.VilleLabel;
  p.GestionnaireProjet = await userServices.GetNameById(p.GestionnaireProjetId ?? 0);
  await Task.WhenAll(p.SousProject.Select(async sp =>
  {
    sp.Avancement = await avancementService.GetLabelById(sp.AvancementId);
  });
});
model.projets = projets;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-31
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 1970-01-01
    相关资源
    最近更新 更多