.net Console.WriteLine如何影响并行执行

lx0bsm1f  于 2022-12-24  发布在  .NET
关注(0)|答案(2)|浏览(223)

我正在玩和学习异步和并行编程。我有一个地址列表,并希望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()行。

o0lyfsai

o0lyfsai1#

您看到的输出行为的差异只与您写入输出的时间点有关。
第二种方法:"并逐个写入控制台"
这是因为任何任务一"完成",就调用编写输出的代码,这发生在不同的时间点,因此您可以看到它们"一个接一个"地输出。
第一种方法:"在等待它们之后,首先把它们全部写出来。"
这是因为你在代码中就是这样做的,等到所有的都完成了,然后按顺序输出你找到的东西。
您的示例不能通过输出行为来判断哪个版本在并行运行方面更好。

  • 实际上,它们在所有实际用途上都是相同的。任务内部Console.WriteLine的开销(与执行实际DNS查找相比)应该可以忽略。*

对于计算密集型的东西来说,情况可能会有所不同,但无论如何,您可能都应该使用Parallel.ForEach
那么你应该在哪里输出呢?这取决于。如果你需要尽快显示信息(这里是DNS查找结果),那么就在任务内部完成。如果可以等到所有的都完成(这可能需要一些时间),那么就在最后完成。

4smxwvx5

4smxwvx52#

对控制台的写入不是异步的。因为控制台默认不是异步的。使用控制台部分,您可以“同步”您的任务。可能:

var task = new Task(async () =>
    {
        orderedClientIp.Address = await ResolveAsync(orderedClientIp.Ip);
        return $"{(orderedClientIp.Ip)} ({orderedClientIp.Ip}) - {orderedClientIp.Count}";
    }).ContinueWith(previousTask => Console.WriteLine(previousTask.Result));

相关问题