0

在这里,我有以下代码:

var tasks = new List<Task>();

var stopwatch = new Stopwatch();
for (var i = 0; i < 100; i++)
{
    var person = new Person { Id = i };
    list.Add(person);
}

stopwatch.Start();
foreach (var item in list)
{
    var task = Task.Run(async () =>
    {
        await Task.Delay(1000);
        Console.WriteLine("Hi");
    });
    tasks.Add(task);
}

await Task.WhenAll(tasks);
stopwatch.Stop();

我假设我将有大约100 秒的秒表结果。但我有1,1092223

我想我错过了一些东西,你能帮我解释一下为什么吗?

4

2 回答 2

2

我假设您的困惑可能来自 await 关键字await Task.Delay(1000);

但这仅适用于任务方法的内部工作。在循环内部,下一次迭代将在执行后立即Task.Run执行。因此,所有任务将连续启动,然后并行运行。(当然,只要系统手头有空闲线程)系统会注意如何、何时以及以何种顺序执行它们。

最后在这一行:

await Task.WhenAll(tasks);

您实际上是在等待其中最慢的(或最后一个开始的)。

为了满足您的期望,您的代码实际上应该如下所示:

public async Task RunAsPseudoParallel()
{
    List<Person> list = new List<Person>();

    var stopwatch = new Stopwatch();
    for (var i = 0; i < 100; i++)
    {
        var person = new Person { Id = i };
        list.Add(person);
    }

    stopwatch.Start();
    foreach (var item in list)
    {
        await Task.Run(async () =>
        {
            await Task.Delay(1000);
            Console.WriteLine("Hi");
        });
    }
    stopwatch.Stop()
}

免责声明:但是这段代码非常荒谬,因为它使用异步功能来实现同步过程。在这种情况下,您可以简单地省略Task.Run调用并使用简单的Thread.Sleep(1000).

于 2020-07-29T11:50:44.080 回答
1

延迟总是近似的。

当任务调度程序选择运行您传递给的委托时,您会受到限制Task.Run。它可能正在执行其他任务并且不愿意启动更多线程。或者,它可能会启动一个新线程——虽然速度不慢,但也不是免费的,而且也需要时间。

您受限于任务调度程序在延迟完成后选择恢复您的代码的时间。

您还受到操作系统调度程序的限制,它可能会将 CPU 时间分配给其他进程/线程并最终延迟执行代码的线程。

因为您要启动多个任务,所以您会看到所有这些每个任务的变量都复合成更大的延迟。

于 2020-07-29T12:40:06.100 回答