我正在玩和学习异步和并行编程。我有一个地址列表,并希望dns解析它们。此外,我为此制作了以下函数:
private static Task<string> ResolveAsync(string ipAddress)
{
return Task.Run(() => Dns.GetHostEntry(ipAddress).HostName);
}
现在,在我解析地址的程序中,思想是使用并行编程:
//getting orderedClientIps before
var taskArray = new List<Task>();
foreach (var orderedClientIp in orderedClientIps)
{
var task = new Task(async () =>
{
orderedClientIp.Address = await ResolveAsync(orderedClientIp.Ip);
});
taskArray.Add(task);
task.Start();
}
Task.WaitAll(taskArray.ToArray());
foreach (var orderedClientIp in orderedClientIps)
{
Console.WriteLine($"{(orderedClientIp.Ip)} ({orderedClientIp.Ip}) - {orderedClientIp.Count}");
}
因此,在这里我们等待所有地址解析完毕,然后在单独的迭代中打印它们。
让我感兴趣的是,如果不是在单独的迭代中打印,我会做这样的事情,会有什么不同:
foreach (var orderedClientIp in orderedClientIps)
{
var task = new Task(async () =>
{
orderedClientIp.Address = await ResolveAsync(orderedClientIp.Ip);
Console.WriteLine($"{(orderedClientIp.Ip)} ({orderedClientIp.Ip}) - {orderedClientIp.Count}");
});
taskArray.Add(task);
task.Start();
}
Task.WaitAll(taskArray.ToArray());
我试过执行,它一个接一个地写入控制台,而在第一个示例中,在等待它们之后将它们全部写出。我认为第一种方法是并行的,更好,但不太确定区别。在异步和并行编程的上下文中,第二种方法有什么不同?第二种方法是否在某种程度上违反了Task.WaitAll()行。
2条答案
按热度按时间o0lyfsai1#
您看到的输出行为的差异只与您写入输出的时间点有关。
第二种方法:"并逐个写入控制台"
这是因为任何任务一"完成",就调用编写输出的代码,这发生在不同的时间点,因此您可以看到它们"一个接一个"地输出。
第一种方法:"在等待它们之后,首先把它们全部写出来。"
这是因为你在代码中就是这样做的,等到所有的都完成了,然后按顺序输出你找到的东西。
您的示例不能通过输出行为来判断哪个版本在并行运行方面更好。
Console.WriteLine
的开销(与执行实际DNS查找相比)应该可以忽略。*对于计算密集型的东西来说,情况可能会有所不同,但无论如何,您可能都应该使用
Parallel.ForEach
。那么你应该在哪里输出呢?这取决于。如果你需要尽快显示信息(这里是DNS查找结果),那么就在任务内部完成。如果可以等到所有的都完成(这可能需要一些时间),那么就在最后完成。
4smxwvx52#
对控制台的写入不是异步的。因为控制台默认不是异步的。使用控制台部分,您可以“同步”您的任务。可能: