【问题标题】:Recommend way to use Task.WhenAll to execute tasks in a loop推荐使用 Task.WhenAll 循环执行任务的方法
【发布时间】:2025-12-03 05:00:02
【问题描述】:

谁能推荐我如何将Task.WhenAll 应用于以下代码

foreach (DataRow row in sap_tickets.Rows)
{
    //#EDIT This is the beginning of the task i want to execute
    picklist = row["absentry"].ToString();
    try
    {
         //call webservice here
         string response = await Ut.updateFulfilment(row["order_number"].ToString());

    }
    catch (Exception)
    {
        //log error to DB
        Ut.FlagOff(picklist, CommonEnums.FLAG_OFF_TYPE.ERROR.ToString());
    }
    //This is the end of the task i want to execute
}

编辑

我的任务由存在于 foreach 循环中的代码组成 他们可以安全地多次调用

【问题讨论】:

  • @Edwin:通常,有比在循环中使用Task.WhenAll 更好的方法。你到底想做什么?
  • @stuartd 我已经编辑了问题以表明这一点
  • @StephenCleary 我正在尝试以并行方式执行存在于 foreach 循环主体中的代码
  • 如果你想同时运行这些,Ut.updateFulfilment( 在第一次调用完成之前多次调用是否安全?
  • 是的@ScottChamberlain 多次调用是安全的

标签: c# async-await task parallel.foreach


【解决方案1】:

如果Ut.updateFulfilment( 是线程安全的,它实际上很容易。只需将 foreach 的主体放入异步函数中,然后将该函数传递给 Select(。将Select( 的结果传递给Task.WhenAll(

async Task YourOriginalFunction(DataTable sap_tickets)
{
    //Be user System.Data.DataSetExtensions.dll is included in the project refrences 
    //to get AsEnumerable() to work.
    var tasks = sap_tickets.AsEnumerable().Select(BodyAsync)
    await Task.WhenAll(tasks);
}

async Task BodyAsync(DataRow row)
{
    picklist = row["absentry"].ToString();
    try
    {
         //call webservice here
         string response = await Ut.updateFulfilment(row["order_number"].ToString());
    }
    catch (Exception)
    {
        //log error to DB
        Ut.FlagOff(picklist, CommonEnums.FLAG_OFF_TYPE.ERROR.ToString());
    }
}

在您点击第一个await 之前,您不会做任何“繁重的工作”,因此您不需要使用Task.Run( 来获取多个线程,一旦您发出网络服务请求,它将立即开始下一个循环foreach,而不是像以前那样等待整个方法体完成后再开始下一个循环。

【讨论】:

  • 我得到 System.Data.Datarowcollection 不包含“选择”的任何定义 ....此时 => sap_tickets.Rows.Select
  • @Edwin 我更新了答案,但是请确保您已将 System.Data.DataSetExtensions.dll 作为项目参考包含在内,否则它将找不到方法。
  • @Edwin 你也可以使用sap_tickets.Rows.Cast<DataRow>().Select(,但我喜欢sap_tickets.AsEnumerable().Select(,因为它更干净一些。
  • 一切正常,Catch 块只执行一次,理想情况下它应该根据我正在考虑传递的数据执行 6 次。任何想法为什么会发生这种情况??
  • catch 块将在每个条目中执行一次,也许FlagOffupdateFulfilment 不像您想象的那样线程安全,导致它不会在应该抛出的时候抛出?
最近更新 更多