在 C# async/await 中,延迟长度会影响控制权何时返回调用者吗?

问题描述 投票:0回答:1

以下代码按预期工作 - 两个服务同时启动。

List<Service> services = [ new Service(), new Service() ];

foreach (Service service in services)
{
    Task task = service.StartAsync();
}

Console.ReadLine();

class Service
{
    public async Task StartAsync()
    {
        await Console.Out.WriteLineAsync($"{DateTime.Now.ToString("HH:mm:ss")}\tStarted");

        await Task.Delay(TimeSpan.FromSeconds(1));

        //Simulate some synchronous work.
        Thread.Sleep(10_000);

        await Console.Out.WriteLineAsync($"{DateTime.Now.ToString("HH:mm:ss")}\tFinished");
    }
}

输出是:

20:32:25     Started
20:32:25     Started
20:32:35     Finished
20:32:35     Finished

但是当你将延迟从

TimeSpan.FromSeconds(1)
更改为
TimeSpan.FromMicroseconds(1)
时,输出为:

20:40:10     Started
20:40:20     Finished
20:40:20     Started
20:40:30     Finished

为什么改变延迟会影响行为?是否存在竞争条件?

c# asynchronous async-await task
1个回答
0
投票

但是当您将延迟从

TimeSpan.FromSeconds(1)
更改为
TimeSpan.FromMicroseconds(1)
...

.NET 计时器无法在亚毫秒时间跨度内触发。任何小于一毫秒的时间跨度都会蒸发为零:

Task task = Task.Delay(TimeSpan.FromMicroseconds(999));
Console.WriteLine(ReferenceEquals(task, Task.CompletedTask)); // True

在线演示.

因此

await Task.Delay(TimeSpan.FromMicroseconds(1));
变为
await Task.CompletedTask;
,这是一个空操作。执行流程同步继续。没有安排。

await Console.Out.WriteLineAsync
也是同步,因为
Console.Out
不会覆盖异步
TextWriter
/
Stream
API 的默认实现,这些 API 都是同步实现的。

结果是你的

StartAsync
方法变得完全同步。除了它的名称和签名之外,它没有任何异步内容。它里面的所有内容都在当前线程上同步运行。如果您想确保服务的执行是并行的,您可以使用
Task.Run
,如下所示:

foreach (Service service in services)
{
    Task task = Task.Run(() => service.StartAsync());
}

这是有效的,因为

Task.Run
function
委托的调用卸载给
ThreadPool

© www.soinside.com 2019 - 2024. All rights reserved.