【发布时间】:2019-10-05 20:22:10
【问题描述】:
我正在尝试理解并行编程,我希望我的 async 方法可以在多个线程上运行。我写了一些东西,但它并没有像我想象的那样工作。
代码
public static async Task Main(string[] args)
{
var listAfterParallel = RunParallel(); // Running this function to return tasks
await Task.WhenAll(listAfterParallel); // I want the program exceution to stop until all tasks are returned or tasks are completed
Console.WriteLine("After Parallel Loop"); // But currently when I run program, after parallel loop command is printed first
Console.ReadLine();
}
public static async Task<ConcurrentBag<string>> RunParallel()
{
var client = new System.Net.Http.HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com");
var list = new List<int>();
var listResults = new ConcurrentBag<string>();
for (int i = 1; i < 5; i++)
{
list.Add(i);
}
// Parallel for each branch to run await commands on multiple threads.
Parallel.ForEach(list, new ParallelOptions() { MaxDegreeOfParallelism = 2 }, async (index) =>
{
var response = await client.GetAsync("posts/" + index);
var contents = await response.Content.ReadAsStringAsync();
listResults.Add(contents);
Console.WriteLine(contents);
});
return listResults;
}
我希望在打印“并行循环之后”之前完成 RunParallel 函数。另外我希望我的 get posts 方法可以在多个线程上运行。
任何帮助将不胜感激!
【问题讨论】:
-
并行与异步不同。一个是在多个线程上运行东西,另一个是在等待某事(通常是 IO,但可能是另一个线程完成某些工作)时不阻塞线程。如果您希望 IO 并行发生,您只需要收集任务并摆脱 Parallel.ForEach
-
async/await不用于并行性,它们有助于异步操作。Parallel.ForEach用于数据并行(在本地处理 100K/1M 项),绝对不用于异步工作。事实上,它不能等待任何异步操作。此代码将同时触发所有请求,并且永远不会收到结果 -
在任何情况下,异步操作已经在另一个线程上运行,或者在完成之前不会打扰它们的创建者。您可以使用例如
var results = Task.WhenAll(Enumerable.Range(1,5).Select(i=>client.GetStringAsync($"posts/{i}")));来启动所有 5 个任务并等待它们的结果而不会阻塞 -
@PanagiotisKanavos 这会在多个线程中运行吗?
-
@PanagiotisKanavos 你会用什么来代替 Parallel.ForEach?我们可以将 ActionBlock 用于数据并行和异步工作吗?
标签: c# parallel-processing task-parallel-library parallel.foreach