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 &#…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
