如何在并行 foreach 中使用 await?
How to use await in a parallel foreach?
所以我花了大半夜的时间试图解决这个问题。
我很幸运昨天被介绍给 parallel.foreach,除了一个细节外,它的工作方式与我希望的一样。
我有以下内容:
Parallel.ForEach(data, (d) =>
{
try
{
MyMethod(d, measurements);
}
catch (Exception e)
{
// logg
}
});
在方法 "MyMethod" 中,我有很多逻辑已经完成,大部分都很好,但是我在获取数据的地方进行了 api 调用,为此我使用了异步任务使用 "await" 让代码等到特定部分被执行然后继续:
private async void MyMethod(PimData pimData, IEnumerable<ProductMeasurements> measurements)
{
try
{
// alot of logic but most relevant part
await Task.WhenAll(ExecuteMeasurmentAndChartLogic(pimData.ProductNumber, entity));
await Task.WhenAll(resourceImportManager.HandleEntityImageFiles(pimData.ProductType + pimData.ProductSize,SwepImageType.Png, ResourceFileTypes.ThreeD, entity, LinkTypeId.ProductResource));
await Task.WhenAll(resourceImportManager.HandleEntityImageFiles(pimData.ProductSketch, SwepImageType.Png, ResourceFileTypes.Sketch, entity, LinkTypeId.ProductResource));
}
catch (Exception e)
{
// logg
}
}
Problems:
1 For starters the loop finishes before all code is finished
2 Second problem is that I get "Task was canceled" in alot of api
calls
3 And third as mentioned above, the code does not wait for each method
to full execute.
我无法让它执行 ExecuteMeasurmentAndChartLogic() 方法中的所有内容
在继续下一步之前。
这给了我以下问题(更多问题):
在这个方法中,我创建了一个项目并将其添加到数据库中,这个项目需要我从 ExecuteMeasurmentAndChartLogic() 内部完成的 api 调用中获得的更多信息,但问题是有几个项目被创建,必须等待其余的数据,这不是我想要的。
旁注:我知道在所有数据都存在之前打包一个项目并添加到数据库中并不是最佳实践,但我正在向 PIM 集成,这个过程很微妙
我想要多个线程 运行 但同时我希望在继续下一个方法之前为每个项目执行完整逻辑。
澄清:
几项运行
每个项目都处理 ALL 在继续执行代码的下一部分之前需要处理的逻辑,通常使用 await 执行此操作。
在上面的代码中,resourceImportManager() 方法在 ExecuteMeasurmentAndChartLogic() 完成之前执行。这是我不想要的。
我使用了 Parallel.ForEach 而不是
Task task1 = Task.Factory.StartNew(() => MyMethod(data, measurements));
Task.WaitAll(task1);
但这并没有多大帮助
对此很陌生,无法理解我哪里做错了。
编辑:
更新了问题
编辑:这是 ExecuteMeasurmentAndChartLogic() 的样子:
public async Task ExecuteMeasurmentAndChartLogic(string productNumber, Entity entity)
{
try
{
GrafGeneratorManager grafManager = new GrafGeneratorManager();
var graphMeasurmentList = await MeasurmentHandler.GetMeasurments(productNumber);
if (graphMeasurmentList.Count == 0) return;
var chart = await grafManager.GenerateChart(500, 950, SystemColors.Window, ChartColorPalette.EarthTones,
"legend", graphMeasurmentList);
await AddChartsAndAddToXpc(chart, entity, productNumber);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
编辑:
背景:
我打电话给 api 以获取大量数据。
对于此数据中的每个项目,我需要进行 api 调用并获取我应用于该项目的数据。
阅读评论后,也让我以不同的方式思考。我也许可以遍历我的所有项目并为它们做次要逻辑并在任务列表中添加一个 url 并创建一个单独的任务来一个一个地执行它。
会保持更新
根本不要使用 Parralel.ForEach
。使您的方法成为 return Task 而不是 void,收集所有任务并像这样等待它们:
Task.WaitAll(data.Select(d => MyMethod(d, someParam)).ToArray());
所以我花了大半夜的时间试图解决这个问题。
我很幸运昨天被介绍给 parallel.foreach,除了一个细节外,它的工作方式与我希望的一样。
我有以下内容:
Parallel.ForEach(data, (d) =>
{
try
{
MyMethod(d, measurements);
}
catch (Exception e)
{
// logg
}
});
在方法 "MyMethod" 中,我有很多逻辑已经完成,大部分都很好,但是我在获取数据的地方进行了 api 调用,为此我使用了异步任务使用 "await" 让代码等到特定部分被执行然后继续:
private async void MyMethod(PimData pimData, IEnumerable<ProductMeasurements> measurements)
{
try
{
// alot of logic but most relevant part
await Task.WhenAll(ExecuteMeasurmentAndChartLogic(pimData.ProductNumber, entity));
await Task.WhenAll(resourceImportManager.HandleEntityImageFiles(pimData.ProductType + pimData.ProductSize,SwepImageType.Png, ResourceFileTypes.ThreeD, entity, LinkTypeId.ProductResource));
await Task.WhenAll(resourceImportManager.HandleEntityImageFiles(pimData.ProductSketch, SwepImageType.Png, ResourceFileTypes.Sketch, entity, LinkTypeId.ProductResource));
}
catch (Exception e)
{
// logg
}
}
Problems:
1 For starters the loop finishes before all code is finished
2 Second problem is that I get "Task was canceled" in alot of api calls
3 And third as mentioned above, the code does not wait for each method to full execute.
我无法让它执行 ExecuteMeasurmentAndChartLogic() 方法中的所有内容 在继续下一步之前。
这给了我以下问题(更多问题):
在这个方法中,我创建了一个项目并将其添加到数据库中,这个项目需要我从 ExecuteMeasurmentAndChartLogic() 内部完成的 api 调用中获得的更多信息,但问题是有几个项目被创建,必须等待其余的数据,这不是我想要的。
旁注:我知道在所有数据都存在之前打包一个项目并添加到数据库中并不是最佳实践,但我正在向 PIM 集成,这个过程很微妙
我想要多个线程 运行 但同时我希望在继续下一个方法之前为每个项目执行完整逻辑。
澄清:
几项运行
每个项目都处理 ALL 在继续执行代码的下一部分之前需要处理的逻辑,通常使用 await 执行此操作。
在上面的代码中,resourceImportManager() 方法在 ExecuteMeasurmentAndChartLogic() 完成之前执行。这是我不想要的。
我使用了 Parallel.ForEach 而不是
Task task1 = Task.Factory.StartNew(() => MyMethod(data, measurements));
Task.WaitAll(task1);
但这并没有多大帮助
对此很陌生,无法理解我哪里做错了。
编辑: 更新了问题
编辑:这是 ExecuteMeasurmentAndChartLogic() 的样子:
public async Task ExecuteMeasurmentAndChartLogic(string productNumber, Entity entity)
{
try
{
GrafGeneratorManager grafManager = new GrafGeneratorManager();
var graphMeasurmentList = await MeasurmentHandler.GetMeasurments(productNumber);
if (graphMeasurmentList.Count == 0) return;
var chart = await grafManager.GenerateChart(500, 950, SystemColors.Window, ChartColorPalette.EarthTones,
"legend", graphMeasurmentList);
await AddChartsAndAddToXpc(chart, entity, productNumber);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
编辑: 背景: 我打电话给 api 以获取大量数据。 对于此数据中的每个项目,我需要进行 api 调用并获取我应用于该项目的数据。
阅读评论后,也让我以不同的方式思考。我也许可以遍历我的所有项目并为它们做次要逻辑并在任务列表中添加一个 url 并创建一个单独的任务来一个一个地执行它。
会保持更新
根本不要使用 Parralel.ForEach
。使您的方法成为 return Task 而不是 void,收集所有任务并像这样等待它们:
Task.WaitAll(data.Select(d => MyMethod(d, someParam)).ToArray());