c# Task.Yield 的作用是什么 它和Task.Delay(1)有区别吗
技术百科
月夜之吻
发布时间:2026-01-02
浏览: 次 Task.Yield()本质是让出当前上下文、强制触发await挂起与恢复,使后续代码延至下一调度周期执行;Task.Delay(1)则是真实等待至少1毫秒,依赖系统计时器且不可靠。
Task.Yield() 的本质是“让出当前上下文,但不引入真实延迟”
它不是“睡一会儿”,而是告诉调度器:“我先不占着了,你爱干啥干啥,等轮到我再继续”。Task.Yield() 返回一个**已创建即完成(completed)但被标记为需异步延续**的 Task——关键在于:它会强制触发一次 await 的“挂起 + 恢复”流程,从而把后续代码推到**下一个调度周期**执行。这意味着:UI 线程不会卡住、线程池线程不会被白占着、await 后的代码一定在下一轮消息循环或线程池调度中运行。
- 它不依赖时间,不计时,不消耗 CPU 做轮询
- 它不阻塞线程,也不释放线程(只是让出控制权)
- 它在有同步上下文(如 WinForms/WPF/Blazor Server)时,会回到原上下文;在线程池环境(
TaskScheduler.Default)中,大概率由另一个线程池线程继续执行
Task.Delay(1) 是“真等 1 毫秒”,行为完全不同
Task.Delay(1) 会启动一个底层计时器(Timer 或 ThreadPool.UnsafeQueueUserWorkItem),并返回一个**尚未完成**的 Task。它必须等到系统时钟走完至少 1ms(实际常更久,受系统精度和调度影响),才触发完成回调。虽然 1ms 很短,但它:引入真实等待、占用计时器资源、可能跨线程回调、且无法保证“下一帧”就执行。
- 在 UI 应用中,
await Task.Delay(1)通常也能让界面响应,但这是靠“等了一小会儿”换来的,不是设计意图 - 在高并发服务端,大量
Task.Delay(1)会创建大量短期计时器,增加内核调度开销 - 它不能替代
Task.Yield()的“切点”作用——比如你想确保某段逻辑不和前序同步代码挤在同一调度单元里,Task.Delay(1)不够可靠(可能仍被调度器连续安排)
实操对比:三行代码就能看出区别
static async Task Demo()
{
Console.WriteLine($"Start: {DateTime.Now:HH:mm:ss.fff}");
await Task.Yield(); // ← 立即让出,下一调度周期恢复
// await Task.Delay(1); // ← 真等至少 1ms,再恢复
Console.WriteLine($"After yield: {DateTime.Now:HH:mm:ss.fff}");
}
调用它后你会看到:Start 和 After yield 的时间戳几乎总在不同毫秒(哪怕只差 0.1ms),因为执行被明确切开了;而换成 Task.Delay(1),两者大概率差 ≥1ms,且可能因系统负载出现 2~15ms 的抖动。
什么时候该用哪个?别混淆核心目的
选 Task.Yield() 当你需要:
- 打破同步执行链,避免 UI 冻结(比如长循环中插入一次让出)
- 确保后续代码不在当前同步上下文“原子块”内执行(如测试异步状态机行为)
- 实现轻量级协作式让权(类似纤程 yield),又不想引入定时器开销
选 Task.Delay(N) 当你需要:
- 真正的延时(重试退避、节流、模拟网络延迟)
- 等待某个时间点之后再做操作
- 配合
CancellationToken实现可取消的等待
顺带提一句:Task.Delay(0) 并不等价于 Task.Yield()——它返回一个已完成任务,await 它不会让出,而是直接同步往下走,这点很多人会误判。
# ai
# 这是
# 也不
# 会儿
# 它不
# 当你
# 计时器
# 下一
# win
# ui
# default
# 循环
# 并发
# 区别
# c#
# 线程
# 异步
# 回调
# wpf
# 挂起
# 干啥
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- 如何在Golang中理解指针比较_Golang地址
- Win11怎么关闭OneDrive同步_Win11
- Win11怎么设置夜间模式_Windows11显示
- c++怎么使用类型萃取type_traits_c+
- Mac怎么开启“任何来源”_Mac安装未签名应用的
- MAC如何安装Git版本控制工具_MAC开发环境配
- 手机php文件怎么变成mp4_安卓苹果打开php转
- LINUX怎么查看进程_LINUX ps命令查看运
- C#如何在一个XML文件中查找并替换文本内容
- MAC如何启用访达侧边栏显示_MAC Finder
- windows 10应用商店区域怎么改_windo
- Win11怎么开启剪贴板历史记录_Windows1
- php订单日志怎么按金额排序_php按订单金额排序
- mac怎么安装adb_MAC配置Android A
- Win11怎么设置开机自动连接宽带_Windows
- Python生成器表达式内存优化_惰性计算说明【指
- Python实现图数据库操作_Neo4j核心CRU
- Windows10怎样设置家长控制_Windows
- Win11怎么压缩文件 Win11自带压缩解压功能
- 如何使用Golang sort排序切片_Golan
- 如何在 Go 中判断变量是否为函数类型
- Go 中实现 Python urllib.quot
- VSC怎样在VSC中调试PHPAPI_接口调试技巧
- Windows电脑键盘突然失灵怎么办?(驱动与硬件
- Windows蓝屏错误0x0000001E怎么修复
- 如何更改Windows资源管理器的默认启动位置?(
- 如何使用正则表达式批量替换重复的“-”模式为固定字
- Win11怎么关闭任务栏小组件_Windows11
- 如何自定义Windows终端的默认配置文件?(Po
- Win11开机速度慢怎么优化_Win11系统启动加
- Win11怎么开启HDR模式_Windows 11
- XSLT怎么生成动态的HTML属性名和标签名
- Win11相机打不开提示错误怎么修_相机权限开启与
- Win11怎么打开旧版计算器_Win11恢复传统计
- 如何使用Golang操作指针变量_Golang解引
- PHP cURL GET请求:正确设置认证与自定义
- Python与MongoDB NoSQL开发实战_
- Windows10系统服务优化指南_Win10禁用
- Windows10蓝屏代码DPC_WATCHDOG
- MySQL 中使用 IF 和 CASE 实现查询字
- XAMPP 启动失败(Apache 突然停止)的终
- Win11此电脑不在桌面上_Windows 11桌
- 如何用正则表达式精确匹配“start”到“end”
- Win11如何设置文件关联 Win11修改特定文件
- Win11如何卸载OneDrive_Win11卸载
- 如何使用Golang构建简易投票统计功能_Gola
- 如何在 Go 同包不同文件中正确引用结构体
- Windows10电脑怎么设置虚拟光驱_Win10
- Python装饰器复用技巧_通用能力解析【教程】
- Win11更新后变慢怎么办_Win11系统更新后卡

QQ客服