c# 在同步方法中使用 Task.Delay

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

我知道接下来要展示的内容是错误的,但我想知道到底发生了什么。由于我的声誉较低,我无法附加图片。

我有.NET 7 API 项目。

我在同步方法(API)中使用

Task.Delay()

using (var client = new HttpClient() { Timeout = System.TimeSpan.FromSeconds(15)})
{
    var response = client.GetAsync("https://...");

    var canProceed = false;    

    while (!canProceed)
    {
        if (response.IsCompleted)
        {
            canProceed = true;
        }
        Task.Delay(25);
    }; 
}

我知道

Task.Delay()
不会拖延。

然后我使用一个单独的控制台应用程序并使用

Parallel.For
点击此 API - 10.000 次。使用 JetBrains dotMemory,我在内存消耗方面得到了可怕的结果。运行点击 Api 的控制台应用程序几秒钟后,API 应用程序的内存从 100mb 增长到 4GB。当我比较两个快照时 - “SurvivedBytes”显示 ConcurrentQueue 拥有 80 字节但保留 3GB。该工具的“内存分配”部分显示 2GB 分配给 TimerQueueTimer,1GB 分配给 Task + DelayPromise

有趣的是,垃圾收集器不会收集内存(我收到了高 GC 压力的警告),除非我多次使用“强制 GC”。

当我将

Task.Delay(25)
替换为
Thread.Sleep(25)
时,API 应用程序在高负载下工作正常 - GC 密集工作,但仍将内存保持在 150mb 以下。

我知道我不能像这样在同步方法中使用

Task.Delay()
,我只是想知道这里发生了什么。

我确实读过这个(以及其他相关主题): Task.Delay 或 Thread.Sleep 在同步方法中暂停执行

不等待

Task.Delay(25);
不会阻塞循环,它只会启动所有底层基础设施,仅此而已,所以基本上您将调用
Task.Delay(25);
直到响应完成,无需任何等待。因此资源消耗。你当然可以用
Task.Delay(25).GetAwaiter().GetResult();
来阻止它,但你真的不应该阻止异步代码。使用
Thread.Sleep
。或者更好 - 让你的方法异步。

c# asynchronous async-await task scheduled-tasks
1个回答
0
投票
不等待

Task.Delay(25);
不会阻塞循环,它只会启动所有底层基础设施,仅此而已,所以基本上您将调用
Task.Delay(25);
直到响应完成,无需任何等待。因此资源消耗。你当然可以用
Task.Delay(25).GetAwaiter().GetResult();
来阻止它,但你真的不应该阻止异步代码。使用
Thread.Sleep
。或者更好 - 让你的方法异步。

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