Dan*_*reh 2 c# task parallel.foreach asp.net-core
我有一个项目列表,对于每个项目,我需要执行几个异步 API 请求并处理响应,我已经看到了几个实现,它们在执行时间方面都很相似,但我想知道它们之间的区别。
方法一
Parallel.ForEach(items, new ParallelOptions { MaxDegreeOfParallelism = 10 }, item =>
{
var response = item.propertyOne.GetAsync().GetAwaiter().GetResult();
//process it
var response = item.propertyTwo.GetAsync().GetAwaiter().GetResult();
//process it
var response = item.propertyThree.GetAsync().GetAwaiter().GetResult();
//process it
});
Run Code Online (Sandbox Code Playgroud)
方法2
Parallel.ForEach(items, new ParallelOptions { MaxDegreeOfParallelism = 10 }, item =>
{
Task.Run(async () =>
{
var response = await item.propertyOne.GetAsync();
}).GetAwaiter().GetResult();
//process it
Task.Run(async () =>
{
var response = await item.propertyTwo.GetAsync();
}).GetAwaiter().GetResult();
//process it
Task.Run(async () =>
{
var response = await item.propertyThreee.GetAsync();
}).GetAwaiter().GetResult();
//process it
});
Run Code Online (Sandbox Code Playgroud)
方法 3假设应用了某种限制机制,以免系统被任务淹没
List<Task> tasksToAwait = new List<Task>();
foreach (var item in items)
{
tasksToAwait.Add(Task.Run(async () =>
{
var response = await item.propertyOne.GetAsync();
//process it
var response = await item.propertyTwo.GetAsync();
//process it
var response = await item.propertyThree.GetAsync();
//process it
}));
}
await Task.WhenAll(taskToAwait);
Run Code Online (Sandbox Code Playgroud)
笔记:
推荐其中哪一项?如果没有,您有何建议?另外,它们有何不同以及为什么存在执行时间差异?
由于您的方法是异步的,因此只需调用所有方法,而不是单独等待它们,而是等待所有方法以确保所有三个异步过程均已完成。然后,您可以await再次使用来解开结果:
// start all asynchronous processes at once for all three properties\nvar oneTask = item.propertyOne.GetAsync();\nvar twoTask = item.propertyTwo.GetAsync();\nvar threeTask = item.propertyThree.GetAsync();\n\n// await the completion of all of those tasks\nawait Task.WhenAll(oneTask, twoTask, threeTask);\n\n// access the individual results; since the tasks are already completed, this will\n// unwrap the results from the tasks instantly:\nvar oneResult = await oneTask;\nvar twoResult = await twoTask;\nvar threeResult = await threeTask;\nRun Code Online (Sandbox Code Playgroud)\n\n一般来说,在处理异步内容时,应不惜一切代价避免调用.GetResult()、.Result或.Wait()。如果你有一个异步进程,这些都不会产生任何好处。
回复您的评论:
\n\n\n\n\n我假设代码会进入并行 foreach 内部,对吧?
\n
不,您不会\xe2\x80\x99Parallel.ForEach在这里使用,因为您仍在调用异步进程。Parallel.ForEach用于将工作加载到多个线程,但 \xe2\x80\x99 不是您想要在此处执行的操作。您拥有可以同时运行的异步进程,而不需要额外的线程。
因此,如果您有很多想要异步调用的东西,只需调用它们并收集 sTask以便稍后等待它们。
\n\n\n但是,如果请求必须是连续的,例如分页响应,其中第一个请求将返回下一页请求的 URL 等等,该怎么办?
\n
然后,您需要使调用相互依赖,await以确保异步过程在继续之前完成。例如,如果propertyTwo调用依赖于propertyOne,那么您仍然可以先进行所有 propertyOne调用,并且仅在这些调用完成后才继续。
如果您将逻辑分成单独的方法,您会发现这变得更容易:
\n\nvar itemTasks = items.Select(item => GetPropertiesOneTwoThreeAsync(item));\nawait Task.WhenAll(itemTasks);\n\nprivate Task GetPropertiesOneTwoThreeAsync(Item item)\n{\n // get the properties sequentially\n var oneResult = await item.propertyOne.GetAsync();\n var twoResult = await item.propertyTwo.GetAsync();\n var threeResult = await item.propertyThree.GetAsync();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n\n另外,如果调用方法不是异步的,
\nTask.WhenAll(oneTask, twoTask, threeTask).GetAwaiter().GetResult()在这种情况下是否合适?
不可以。从同步方法调用异步方法通常不是您应该做的事情。如果调用异步方法,则应该使调用方法也异步。有多种方法可以实现这一点,但您将不得不处理潜在的僵局,并且通常应该知道您在做什么。另请参阅这个问题。
\n| 归档时间: |
|
| 查看次数: |
1448 次 |
| 最近记录: |