1. 原因

在日常开发中,Task.Delay 是一个常用的异步延迟方法。然而,Task.Delay 的定时并不总是非常准确。例如:

  • 系统负载 Task.Delay 的定时精度可能会受到系统负载的影响。如果系统负载较高,CPU 和其他资源被大量占用,任务调度可能会被延迟,从而导致 Task.Delay 的实际延迟时间超过预期。

  • 任务调度 Task.Delay 是基于任务调度器的,而任务调度器的调度精度可能会受到操作系统的影响。操作系统的任务调度器会根据系统的整体负载和优先级来调度任务,这可能会导致 Task.Delay 的实际延迟时间不够精确。

  • 定时器精度 Task.Delay 使用的是系统定时器,而系统定时器的精度可能会受到硬件和操作系统的限制。不同的操作系统和硬件平台可能会有不同的定时器精度,这也会影响 Task.Delay 的精度。

  • 电源管理 在某些情况下,电源管理策略(如节能模式)可能会影响任务调度和定时器的精度。例如,在节能模式下,CPU 可能会降低频率或进入休眠状态,从而影响 Task.Delay 的精度。

  • GC(垃圾回收) 在 .NET 中,垃圾回收(GC)可能会暂停所有托管线程,从而影响 Task.Delay 的精度。如果在 Task.Delay 期间发生了垃圾回收,实际的延迟时间可能会超过预期。

以下是一个示例代码,展示了如何使用 Task.DelayStopwatch 来测量实际延迟时间,以便更好地理解 Task.Delay 的精度:

using System;
using System.Diagnostics;
using System.Threading.Tasks; public class Program
{
public static async Task Main(string[] args)
{
int delayMilliseconds = 1000; // 1秒 Stopwatch stopwatch = Stopwatch.StartNew();
await Task.Delay(delayMilliseconds);
stopwatch.Stop(); Console.WriteLine($"Expected delay: {delayMilliseconds} ms");
Console.WriteLine($"Actual delay: {stopwatch.ElapsedMilliseconds} ms");
}
}

在这个示例中,我们使用 Stopwatch 来测量 Task.Delay 的实际延迟时间。你可以运行这个示例代码,观察实际延迟时间与预期延迟时间之间的差异。

2. 更加精准的解决方案对比

为了实现更高精度的定时,我们可以使用 System.Threading.TimerSystem.Diagnostics.Stopwatch。以下是这两种方法的对比示例:

2.1. 使用 System.Threading.Timer

System.Threading.Timer 提供了更高精度的定时控制,可以避免 Task.Delay 的一些不准确性。

using System;
using System.Threading;
using System.Threading.Tasks; public class TimerExample
{
public async Task ExecuteWithTimer(int delayMilliseconds)
{
var tcs = new TaskCompletionSource<bool>();
using (var timer = new Timer(_ => tcs.SetResult(true), null, delayMilliseconds, Timeout.Infinite))
{
await tcs.Task;
}
}
}

2.2. 使用 System.Diagnostics.Stopwatch

Stopwatch 可以用来精确测量时间间隔,并结合 Task.Delay 实现更高精度的定时控制。

using System;
using System.Diagnostics;
using System.Threading.Tasks; public class StopwatchExample
{
public async Task ExecuteWithStopwatch(int delayMilliseconds)
{
Stopwatch stopwatch = Stopwatch.StartNew();
while (stopwatch.ElapsedMilliseconds < delayMilliseconds)
{
await Task.Delay(1); // 短暂延迟以避免忙等待
}
}
}

2.3. 使用示例

public class Program
{
public static async Task Main(string[] args)
{
int delayMilliseconds = 1000; // 1秒 // 使用 Task.Delay
Stopwatch stopwatch1 = Stopwatch.StartNew();
await Task.Delay(delayMilliseconds);
stopwatch1.Stop();
Console.WriteLine($"Task.Delay - Expected delay: {delayMilliseconds} ms, Actual delay: {stopwatch1.ElapsedMilliseconds} ms"); // 使用 System.Threading.Timer
var timerExample = new TimerExample();
Stopwatch stopwatch2 = Stopwatch.StartNew();
await timerExample.ExecuteWithTimer(delayMilliseconds);
stopwatch2.Stop();
Console.WriteLine($"Timer - Expected delay: {delayMilliseconds} ms, Actual delay: {stopwatch2.ElapsedMilliseconds} ms"); // 使用 System.Diagnostics.Stopwatch
var stopwatchExample = new StopwatchExample();
Stopwatch stopwatch3 = Stopwatch.StartNew();
await stopwatchExample.ExecuteWithStopwatch(delayMilliseconds);
stopwatch3.Stop();
Console.WriteLine($"Stopwatch - Expected delay: {delayMilliseconds} ms, Actual delay: {stopwatch3.ElapsedMilliseconds} ms");
}
}

3. 总结

虽然 Task.Delay 在大多数情况下是足够准确的,但它确实可能受到系统负载、任务调度、定时器精度、电源管理和垃圾回收等因素的影响,导致定时不够精确。通过使用 System.Threading.TimerSystem.Diagnostics.Stopwatch,我们可以实现更高精度的定时控制。

深入理解 Task.Delay 的定时精度及其影响因素的更多相关文章

  1. Task C# 多线程和异步模型 TPL模型 【C#】43. TPL基础——Task初步 22 C# 第十八章 TPL 并行编程 TPL 和传统 .NET 异步编程一 Task.Delay() 和 Thread.Sleep() 区别

    Task C# 多线程和异步模型 TPL模型   Task,异步,多线程简单总结 1,如何把一个异步封装为Task异步 Task.Factory.FromAsync 对老的一些异步模型封装为Task ...

  2. 15.3 Task Task.Yield和Task.Delay说明

    https://blog.csdn.net/hurrycxd/article/details/79827958 书上看到一个Task.Yield例子,Task.Yield方法创建一个立即返回的awai ...

  3. 理解Task和和async await

    本文将详解C#类当中的Task,以及异步函数async await和Task的关系 一.Task的前世今生 1.Thread 一开始我们需要创建线程的时候一般是通过Thread创建线程,一般常用创建线 ...

  4. Thread.Sleep vs. Task.Delay

    We use both Thread.Sleep() and Task.Delay() to suspend the execution of a program for some given tim ...

  5. .Net4.0如何实现.NET4.5中的Task.Run及Task.Delay方法

    前言 .NET4.0下是没有Task.Run及Task.Delay方法的,而.NET4.5已经实现,对于还在使用.NET4.0的同学来说,如何在.NET4.0下实现这两个方法呢? 在.NET4.0下, ...

  6. Task.Delay() 和 Thread.Sleep() 区别

    1.Thread.Sleep 是同步延迟,Task.Delay异步延迟. 2.Thread.Sleep 会阻塞线程,Task.Delay不会. 3.Thread.Sleep不能取消,Task.Dela ...

  7. Task.Delay方法的2个应用实例,单元测试等待,限时限次下载远程资源

    如果想让程序异步等待一段时间,可以考虑使用Task.Delay方法. 比如,在单元测试中模拟一个异步操作. static async Task<T> DelayedResult<T& ...

  8. Thread.Sleep(1000) 、Task.Delay(1000).Wait() 区别

    public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken){    if (millise ...

  9. task.delay 和 thread.sleep

    1.Thread.Sleep 是同步延迟. Task.Delay异步延迟. 2.Thread.Sleep 会阻塞线程,Task.Delay不会. 3.Thread.Sleep不能取消,Task.Del ...

  10. C#异步延迟Task.Delay

    一. 1.Task.Delay实质是创建一个任务,再任务中开启一个定时间,然后延时指定的时间2.Task.Delay不和await一起使用情况,当代码遇到Task.Delay一句时,创建了了一个新的任 ...

随机推荐

  1. DOM – MutationObserver

    介绍 它和 IntersectionObserver, ResizeObserver 差不多, 都是观察 element 变化的. 它可以观察元素的 attribute 增加, 移除, 修改, app ...

  2. Go runtime 调度器精讲(十):异步抢占

    原创文章,欢迎转载,转载请注明出处,谢谢. 0. 前言 前面介绍了运行时间过长和系统调用引起的抢占,它们都属于协作式抢占.本讲会介绍基于信号的真抢占式调度. 在介绍真抢占式调度之前看下 Go 的两种抢 ...

  3. Python — 循环语句

    while循环语句 语法: 嵌套使用: for循环语句:(for循环外部不允许访问临时变量) 语法: 使用: 待处理的数据集: range语句: 嵌套for循环: continue: break: 随 ...

  4. 关于 CLOI 头像&博客主题征集

    是这样的,开了一个新号准备做一个官号,当作一个公告栏(?),大家访问博客或者看消息也方便 现在苦于脑袋比较笨,想不出头像来,有意者可以帮设计下 此外,还(选择性地)需要一个博客主题,主要是简洁,打开会 ...

  5. C#爬取动态网页上的信息:B站主页

    目录 简介 获取 HTML 文档 解析 HTML 文档 测试 参考文章 简介 动态内容网站使用 JavaScript 脚本动态检索和渲染数据,爬取信息时需要模拟浏览器行为,否则获取到的源码基本是空的. ...

  6. Win10 LTSC 从 2019(1809) 升级到 2021(21H2) 后找回丢失的 WSL

    Win 10 LTST 2019 升级 2021 很简单,直接挂载 ISO 镜像以后,运行 setup.exe,剩下的就是耐心等待了. 升级完成后,用户信息和安装的软件基本上都在,VM15 启动的时候 ...

  7. 揭秘!尤雨溪成立的VoidZero如何改变前端世界

    前言 Vue和Vite之父尤雨溪宣布成立公司 VoidZero,目前已经融资3200万.这篇文章欧阳将带你了解VoidZero是如何改变javascript的世界! 关注公众号:[前端欧阳],给自己一 ...

  8. 未来“数”于你 | 墨天轮携手 Vertica 发布技术文章征集令,双重大奖蓄势待“发”

    作为新一代数据分析平台,Vertica凭借高性能.高可用性以及混合模式部署的底层架构等特点,为国内电信.金融行业提供了较多的整体解决方案. 今天,Vertica 限时开放体验,同时,MacBook P ...

  9. 树形结构体按照 sort 进行排序先按照字母排序 然后按照数字排序

    // 先按照字母排序 然后按照数字排序 function sortListByLetter(arr) { return arr.sort((a, b) => { if (isNaN(a.name ...

  10. js实现控制音乐播放

    js实现控制音乐播放 用js实现控制音乐播放其实很简单,但是第一次去做可能会遇到一点点小问题. 比如说我自己,第一次想实现一个播放器效果,然后在网上搜寻半天照着自己的理解写下如下代码:  <!D ...