C# Thread.Sleep(0)有什么用?
一、理论分析
回答这个要先从线程时间精度(时间片)开始说起。很多参考书说,默认情况下,时间片为15ms 左右,但是这是已经过时的知识。在老的 Windows 操作系统里,应用程序模式时时间片 15ms 左右,准确一点是15.625 左右。服务器模式是其双倍。但是在微软推行.Net 普及 Task之后,规则已经改动,并且做了精细的调节。现在Win10的时间精度为1ms(不用担心谷歌浏览器修改时间精度了),Win2013服务器的时间精度为7ms,使用微软提供的测试工具可以测出来:ClockRes - Sysinternals | Microsoft Learn

命令行:powercfg /energy
我们可以通过它可以更直观的看出:

因为有这个请求在,所以无论如何最低的计时器分辨率都只能为1ms。
所以,现在Win10 默认状态下,Sleep(1) 占时不再是15ms,而是1ms 左右:


1120us 即 1.12ms
下面现在正式回答,Thread.Sleep(0),Thread.Yield(),Thread.Sleep(1) 有什么不同:首先,Thread.Sleep 只是放弃时间片的剩余时间,让系统重新选择调度一个合适的线程(其优先级等于或者高于当前线程)。在没有其他活动线程的情况下,使用Sleep(0) 还是选上原来线程,即连任,如果连任了,系统不会对其做上下文切换,所以有:

由上面的图片可知耗时为18us左右,即0.018ms
其次,Thread.Yield() 是什么呢?跟 Thread.Sleep 有点像,但是它跟 Thread.Sleep(0) 有点区别:系统选择继任时可以选择优先级比原来低的线程。最后,Thread.Sleep(1) 是什么情况呢?前面说了,Thread.Sleep(0) 只是放弃时间片的剩余时间,让系统重新选择调度一个合适的线程。但是 Thread.Sleep(1) 却让当前线程沉睡了(即使只有1ms )。也就是说,主动放弃下次竞选,所以不可能连任,系统上下文必然发生切换(优先级低于原线程的家伙也有机会)。
二、最后总结一下Sleep(0)的用途
1)在图形界面程序中,使用Thread.sleep(0)可以避免长时间运行的任务阻塞UI线程的执行。例如在GUI程序中,当用户通过按钮点击或其他事件触发某个任务时,在该任务完成前可能需要等待某个数据加载、文件下载或其他操作完成。如果不使用Thread.sleep(0),就可能导致主线程阻塞而导致程序无响应。
2)在多线程爬虫程序中,使用Thread.sleep(0)可以有效地限制连接网站的频率,避免过于频繁访问同一目标网站而被封禁IP。例如,在高并发情况下,为了提高效率,某些爬虫程序会采用多线程方式进行网站抓取,这样往往需要控制每个线程之间的请求频率,以避免对目标网站造成负担或被视作恶意攻击。
3)在多线程程序中,使用Thread.sleep(0)可以优化线程调度算法,使得程序更加平滑和高效。例如在Java Web应用中,Tomcat服务器等Web容器采用线程池来管理客户端请求。为了避免某些线程占用关键资源导致其他线程无法响应,可以使用Thread.sleep(0)控制每个线程之间的竞争性,使得整个程序稳定、流畅地运行。
三、效率方面影响
Thread.Sleep(N)会严重影响当前线程中循环的运行效率,原因上面已经说明的很清楚了,上下文切换+线程竞争,所以在高速定时器的应用中:
1、Timer的Period小于10ms,精度会很差,Timer不能满足精度要求,在高速定时器中不推荐用Timer
Timer timer = new Timer(TimerCallback, null, 0, 2);
timer.Change(0, 2);long times = 0;
void TimerCallback(object sender)
{times++;Thread.Sleep(1);
}
运行一分钟后的结果:3767,远低于1000/2*60=30000
2、用for循环实现Timer的功能,不管是Task.Delay还是Thread.Sleep都实现不了小于10ms(>100HZ的精度)
1) 使用 Task.Delay 和 async/await:对于10ms以下精度不够
Delay(TimeSpan.FromMilliseconds(2), null);public async Task Delay(TimeSpan interval, Func<Task> func)
{while (true){await Task.Delay(interval);times++;}
}
运行一分钟后的结果:3729,远低于1000/2*60=30000
2)使用 Thread.Sleep:精度稍微好些,但是不够
DelaySleep();public async Task DelaySleep()
{Task.Run(() =>{while (true){Thread.Sleep(2);times++;}});
}
运行一分钟后的结果:19599,还是低于1000/2*60=30000
3、解决思路:Timer大时间里面写循环
DelayLoop(TimeSpan.FromMilliseconds(1000), func);public async Task DelayLoop(TimeSpan interval, Action func)
{while (true){await Task.Delay(interval);func();}
}private void func()
{for(int imm = 0; imm<500; imm++){Thread.Sleep(0);lock (this){times++;}}
}
运行一分钟后的结果:29000,稍微低于1000/2*60=30000,由于是手动一分钟后点击,没有写成一分钟自动停止,所以存在误差,有兴趣的同学可以测试下,可以满足高速定时器功能,已在项目中使用
参考资料:
1、(43 封私信) C# Thread.Sleep(0)有什么用? - 知乎 (zhihu.com)
2、https://blog.csdn.net/weixin_73077810/article/details/130519033
--以上。
相关文章:
C# Thread.Sleep(0)有什么用?
一、理论分析 回答这个要先从线程时间精度(时间片)开始说起。很多参考书说,默认情况下,时间片为15ms 左右,但是这是已经过时的知识。在老的 Windows 操作系统里,应用程序模式时时间片 15ms 左右࿰…...
二十四、【参考素描三大面和五大调】
文章目录 三种色面(黑白灰)五种色调 这个可以参考素描对物体受光的理解:素描调子的基本规律与素描三大面五大调物体的明暗规律 三种色面(黑白灰) 如下图所示,我们可以看到光源是从亮面所对应的方向射过来的,所以我们去分析图形的时候,首先要…...
【Python 千题 —— 基础篇】进制转换:十进制转二进制
题目描述 题目描述 计算机底层原理中常使用二进制来表示相关机器码,学会将十进制数转换成二进制数是一个非常重要的技能。现在编写一个程序,输入一个十进制数,将其转换成二进制数。 输入描述 输入一个十进制数。 输出描述 程序将输入的…...
[ spring boot入门 ] java: 错误: 无效的源发行版:17
因为我目前idea中使用的是jdK8,而在pom.xml文件里是17,所以我需要将所有地方修改为jdk8 pom.xml的jdk版本为8 maven的setting.xml文件 jdk为8 还有Java Compiler 还有Project Structure 里面的project 和 module...
【计算机组成体系结构】电路基本原理与加法器设计
一、算术逻辑单元—ALU 1.基本的逻辑运算(1bit的运算) 基本逻辑运算分为,与、或、非。大家应该很熟悉了,与:全1为1,否则为0。或:全0为0,否则为1。非:取反。三个基本的逻…...
MyBatisPlus之基本CRUD、常用注解
文章目录 前言一、MyBatisPlus简介1.简介2.特性 二、基本CRUD1.依赖2.搭建基本结构3.BaseMapper4.使用插入删除(1)通过id删除记录(2)通过id批量删除记录(3)通过map条件删除记录 修改查询(1&…...
采集EtherNET/IP转Profinet在西门子plc中的应用
远创智控网关YC-EIPM-PN,让你的设备和云平台实时连接! 远创智控YC-EIPM-PN网关产品支持各种数据接口,无论是工业领域的仪表、PLC、计量设备,还是设备数据,都能实时采集并整合。它将这些设备中的运行数据、状态数据等信…...
Paddle build_cinn_pass_test源码阅读(fluid目录下)
代码位置在 paddle\fluid\framework\paddle2cinn\build_cinn_pass_test.cc ,因为paddle CINN和PIR部分依旧在高频更新,所以各位看到的可能和我的不一样 inline bool CheckNodeExisted(const std::unordered_set<Node*>& nodes,const std::str…...
函数调用:为什么会发生stack overflow?
在开发软件的过程中我们经常会遇到错误,如果你用 Google 搜过出错信息,那你多少应该都访问过Stack Overflow这个网站。作为全球最大的程序员问答网站,Stack Overflow 的名字来自于一个常见的报错,就是栈溢出(stack ove…...
git log
git log -p 是一个用于显示git commit历史的命令,它会展示每个commit的详细信息,包括每个修改文件的清单、添加/删除的行所在的位置以及具体的实际更改。这个命令能够让用户深入了解仓库的历史记录。 与git log相比,git log -p 提供了更多的…...
在面试提问环节应该问那些内容
在面试提问环节应该问那些内容 薪资和福利: 你可以询问关于薪资、福利和其他福利待遇的细节,包括工资结构、健康保险、退休计划、带薪休假等。 了解关于加班、绩效奖金和涨薪机会的信息。 工作时间和灵活性: 询问工作时间、工作日和工作日…...
【vb.net】轻量JSON序列及反序列化
这个代码写的有点时间了,可能有点小bug,欢迎评论区反馈 作用是将Json文本转化成一个HarryNode类进行相关的Json对象处理或者读取,也可以将一个HarryNode对象用ToString变为Json文本。 举例: 1、读取节点数据 dim harryNode N…...
【Vue】vue2与netcore webapi跨越问题解决
系列文章 C#底层库–记录日志帮助类 本文链接:https://blog.csdn.net/youcheng_ge/article/details/124187709 文章目录 系列文章前言一、技术介绍二、问题描述三、问题解决3.1 方法一:前端Vue修改3.2 方法二:后端允许Cors跨越访问 四、资源…...
SpringSecurity + jwt + vue2 实现权限管理 , 前端Cookie.set() 设置jwt token无效问题(已解决)
问题描述 今天也是日常写程序的一天 , 还是那个熟悉的IDEA , 还是那个熟悉的Chrome浏览器 , 还是那个熟悉的网站 , 当我准备登录系统进行登录的时候 , 发现会直接重定向到登录页 , 后端也没有报错 , 前端也没有报错 , 于是我得脸上又多了一张痛苦面具 , 紧接着在前端疯狂debug…...
【21】c++设计模式——>装饰模式
装饰模式的定义 装饰模式也可以称为封装模式,所谓的封装就是在原有行为之上进行扩展,并不会改变该行为; 例如网络通信: 在进行网络通信的时候,数据是基于IOS七层或四层网络模型(某些层合并之后就是四层模型…...
【博客707】模版化拆解并获取victoriametrics的metricsql各个元素
golang解析victoriametrics的metricsql 场景: 需要拆解metricsql中的部分元素,比如:rollup function,label filter等需要对语法合法性进行判断,同时拒绝某些查询函数我们需要拆解metricsql并进行改造 使用victoriam…...
nodejs + express 实现 http文件下载服务程序
nodejs express 实现 http文件下载服务程序, 主要包括两个功能:指定目录的文件列表,某个文件的下载。 假设已经安装好 nodejs ; cd /js/node_js ; 安装在当前目录的 node_modules/ npm install express --save npm install express-gene…...
Qt多文本编辑器项目实战
0x00 引言 本文将详细讲解如何使用Qt实现一个多文本编辑器。涉及的话题包括:Qt框架基础、窗体布局、文本编辑、拓展功能等等。 在阅读本文之前,你需要掌握基本的C编程知识和Qt框架的使用方法。 0x01 新建Qt项目 在Qt Creator中,新建一个Q…...
CVE-2017-7529 Nginx越界读取内存漏洞
漏洞概述 当使用Nginx标准模块时,攻击者可以通过发送包含恶意构造range域的header请求,来获取响应中的缓存文件头部信息。在某些配置中,缓存文件头可能包含后端服务器的IP地址或其它敏感信息,从而导致信息泄露。 影响版本 Ngin…...
力扣每日一题136:只出现一次的数字
题目描述: 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。 示例 1 &#…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
