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
- 如何在Golang中处理通道发送接收错误_防止阻塞
- c++协程和线程的区别 c++异步编程模型对比【核
- Win11怎么开启游戏工具栏_Windows11
- Windows10如何彻底关闭自动更新_Win10
- ACF 教程:正确更新嵌套在多层 Group 字段
- Win11怎么用设置清理回收站_Win11设置清理
- Python模块的__name__属性如何由导入方
- Win11怎么把图标拖到任务栏_Win11固定应用
- Windows10如何更改计算机工作组_Win10
- Mac怎么给文件夹加密_Mac创建加密磁盘映像教程
- PHP接收参数值为空怎么办_判断和处理空参数方法说
- Windows10系统怎么查看硬盘健康_Win10
- Windows蓝屏错误0x00000018怎么处理
- Windows系统时间服务错误_W32Time服务
- 如何使用Golang实现跨域请求支持_Golang
- Win11怎么关闭键盘按键音_Win11禁用打字声
- 如何在 Go 中正确反序列化多个同级 XML 元素
- Windows如何拦截腾讯视频广告_Windows
- 如何更改Windows资源管理器的默认启动位置?(
- php485读数据时阻塞怎么办_php485非阻塞
- Windows10电脑怎么设置防火墙出站规则_Wi
- Win11怎么关闭用户账户控制UAC_Window
- php与c语言在嵌入式中有何区别_对比两者在硬件控
- Mac系统更新下载慢或失败怎么办_解决macOS升
- Win11截图快捷键是什么_Win11自带截图工具
- How to Properly Use NumPy
- c# 如何深拷贝和浅拷贝
- Win10如何关闭安全中心所有通知 Win10禁用
- Win11怎么关闭边缘滑动手势_Windows11
- Windows10电脑怎么设置虚拟光驱_Win10
- 如何关闭Win10自动更新更新_Win10系统自动
- 为什么本地php环境运行php脚本卡顿_php执行
- windows如何禁用驱动程序强制签名_windo
- Win10怎么查看内存时序参数_Win10CPU-
- Win11声音忽大忽小怎么办 Win11音频增强功
- Python函数接口文档化_自动化说明【指导】
- Win10如何卸载WindowsDefender_
- Python与Docker容器化部署实战_镜像构建
- Windows服务持续崩溃怎样修复_系统服务保护机
- Win11如何关闭小娜Cortana Win11禁
- 如何使用Golang实现云原生应用弹性伸缩_自动应
- Win10怎么卸载剪映_Win10彻底卸载剪映方法
- Win11如何设置自动关机 Win11定时关机命令
- WindowsUSB驱动安装异常怎么办_USB驱动
- c++中如何求一个数的平方根_c++ sqrt函数
- Win11怎么打开注册表_Windows 11注册
- php内存溢出怎么排查_php内存限制调试与优化方
- ACF 教程:如何正确更新嵌套在多层 Group
- c++怎么处理多线程死锁_c++ lock_gua

QQ客服