为什么要放弃使用Thread.Sleep
前言
此文并不是说要完全放弃使用Thread.Sleep,而是要说明在符合哪些情况下使用!
场景
很多时候,我们会需要一个定时服务来处理业务。
但并不是死死的每隔N分钟执行一次那种,而是在一次处理完后,算好下一次处理的时间点。
当到达此时间点,触发程序重新开始执行代码。
普遍做法
普遍的情况下,都是使用while(true){Thread.Sleep()}来实现,废话不多话,看代码版本1:
class Program
{
static void Main(string[] args)
{
var workLists = new List<string>() { "任务1", "任务2", "任务3", "任务4" };
foreach (var task in workLists)
{
var thread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(Work.DoWork));
thread.Start(task);
}
}
}
class Work
{
public static void DoWork(object target)
{
var taskType = target as string;
var interval = 1 * 60 * 1000;//处理失败,1分钟后重试
var maxTimes = 5;
var retryTimes = 0;
while (true)
{
while (retryTimes < maxTimes)
{
var ok = Proccess(taskType);
if (ok)
{
retryTimes = maxTimes;
}
else
{
retryTimes++;
System.Threading.Thread.Sleep(interval);
}
}
var tim = GetTotalMillisecondsForNext();//计算离下一次开始处理的时间
System.Threading.Thread.Sleep(tim);//挂起一段时间后,重新唤醒
retryTimes = 0;
}
}
private static bool Proccess(string taskType)
{
Console.WriteLine("开始执行处理:{0}", taskType);
return true;
}
private static int GetTotalMillisecondsForNext()
{
//这里根据自己的业务来决定
return 2 * 1000;
}
}
代码简单易懂。
分析
版本1中,循环强制创建线程,并使用System.Threading.Thread.Sleep(tim)来挂起线程,然后重新唤醒。
这种方式不好之处在于:占用系统线程资源,是一种浪费。如同占着茅坑不拉屎!线程是一种十分宝贵的资源,创建,销毁,切换 都是相当耗性能的。
当Sleep的时候,就等于说:现在我不用,但是你也别想用。你要用?自己去Create一个。
有的人说,Sleep的时候 不占用CPU啊!对,是不占用CPU ,但是占着线程资源,阻碍系统的线程调度!
可以参考下这文章
Threads are a limited resource, they take approximately 200,000 cycles to create and about 100,000 cycles to destroy. By default they reserve 1 megabyte of virtual memory for its stack and use 2,000-8,000 cycles for each context switch. This makes any waiting thread a huge waste.
改进
使用System.Timers.Timer来改进我们的程序。当执行处理业务的代码时,首先把timer停止,处理完毕后,算好一次执行的时间点,赋给timer并启动,看代码版本2
class Program
{
static void Main(string[] args)
{
var workLists = new List<string>() { "任务1", "任务2", "任务3", "任务4" };
Parallel.ForEach(workLists,
},
(task) => { new Work2() { TaskType = task }.DoWork(); });
Console.ReadLine();
}
}
class Work2
{
private Timer _workTimer;
public string TaskType { get; set; }
public void DoWork()
{
_workTimer = new System.Timers.Timer();
_workTimer.Interval = ;
_workTimer.Elapsed += new ElapsedEventHandler(TimerHanlder);
_workTimer.Start();
}
private void TimerHanlder(object sender, ElapsedEventArgs e)
{
_workTimer.Stop();
* * ;//处理失败,1分钟后重试
;
;
while (retryTimes < maxTimes)
{
var ok = Proccess();
if (ok)
{
retryTimes = maxTimes;
}
else
{
retryTimes++;
System.Threading.Thread.Sleep(interval);
}
}
var times = GetTotalSecondsForNext();
Console.WriteLine("{0}秒后重新执行", times);
_workTimer.Interval = times * ;//计算离下一次开始处理的时间
_workTimer.Start();
}
private bool Proccess()
{
Console.WriteLine("开始执行处理:{0}", TaskType);
return true;
}
private int GetTotalSecondsForNext()
{
//这里根据自己的业务来决定
;
}
}
特别说明一下:Main方法中的Console.ReadLine();很重要,让主线程处于等待的状态,子线程就可以一直执行下去不中断
总结
1:使用Task,而不是使用new System.Threading.Thread。是否要创建线程,应该让系统来决定,利用可复用资源
2: System.Threading.Thread.Sleep(interval);只合适在 "有限度的 " 循环场景中,比如 最多重试N次、倒计时等等
如果不对之处,请各位斧正!
为什么要放弃使用Thread.Sleep的更多相关文章
- 为什么要放弃 JSP?他们终于给出了答案
前言 以前的项目大多数都是Java程序猿又当爹又当妈,既搞前,又搞后端. 随着时代的发展,渐渐的许多大中小公司开始把前后端的界限分的越来越明确,前端工程师只负责前端的事情,后端工程师只管后端的事情.正 ...
- it小小鸟
It小小鸟观后感 每个人的理想目标都是不同的,很多人有自己的理想.却被困于现实而止步不前.一篇<it小小鸟>让我却懂得,一个人如果想有所作为,就不能止步不前.光有一个远大的理想是然并卵的. ...
- The Zero
TOday is just a alpha, but there isnot 欧米伽. 编程,是你选的,是你学的,也是你喜欢的,更是你追求的.为什么要放弃塔!. 加油! 为自己. #include&l ...
- Ueditor上传图片到本地改造到上传图片到云存储
作为新手说多了都是泪啊!我特别想记录一下作为菜鸟时的坑.看看以后是否会看着笑出来. 为什么要改到云存储上就不说了.好处多多. 视频教程上使用的又拍云同时也提到了七牛云.下来我自己也查了下.又拍云是试用 ...
- 从底层角度看ASP.NET-A low-level Look at the ASP.NET...
从更低的角度 这篇文章在一个底层的角度来关注一个web请求怎样到达asp.net框架,从web服务器,通过ISAPI.看看这些后面发生了什么,让我们停止对asp.net的黑箱猜想.ASP.NET是一个 ...
- 所有设计复杂的ORM都是浮云
很久没有写文章了. 一直很忙,不是很有时间整理. 今天主要是来吐槽下那些设计很复杂的ORM的. 项目做的越多,越觉得ORM这个东西设计的太复杂实在是没什么意义. 比较推崇Dapper这样比较简单,效率 ...
- THUWC2019爆零记
Day -1 现在在机房里,准备敲敲板子什么的. 今天晚上放假诶,要好好睡一下.好好睡是不可能的,这辈子不可能的. Day 0 现在在酒店,\(lwh\)神仙在超越,我打了个\(treap\)的板子就 ...
- Appium+python自动化5-Appium Inspector
前言 appium Inspector从入门到放弃!反正你都打开了,那就看下为什么要放弃吧! Appium Inspector是appium自带的一个元素定位工具,上一篇介绍了如何使用uiaut ...
- 关于ADO一个容易被忽视的问题!UpdateBatch [问题点数:0分]
这是一个常见但容易被忽视的问题,旧贴有问及但没答案,因此提高分数.相信大家常这样使用Cache模式:ADOConnection1.BeginTrans;Try ADODataSet1.UpdateBa ...
随机推荐
- geoserver使用curl发布 imagemosaic
1.//create workspace curl -v -u admin:geoserver -XPOST -H "Content-type: text/xml" -d ...
- bootstrap表格内容跑到表格外面的处理办法
http://stackoverflow.com/questions/21587813/bootstrap-responsive-table-content-wrapping td写下这个样式即可.& ...
- Daily Scrum 12.18
对于老师课上所问为什么燃尽图(图如下)的完成小时数增加的问题,我们的理解是完成小时数是完成迭代2所需要的总共时间,当加入任务的时候,也就是蓝色部分增长的时候,完成小时数就会增加. 今日大家都在做编译实 ...
- 20145202、20145225、20145234 《信息安全系统设计基础》实验五 简单嵌入式WEB 服务器实验
实验内容 1.配置环境 2.使用vi 编辑器阅读理解源码 2.编译应用程序 运行 make 产生可执行文件httpd 3.下载调试 使用 NFS 服务方式将HTTPD 下载到开发板上,并拷贝测试用的网 ...
- tomcat 解决端口8080冲突
这样的问题有时会因为eclipse等IDE使用bug导致. 解决方法: 使用dos 命令 运行---cmd--netstat -ano|findstr 8080 键入命令后,dos下会显示正在使用80 ...
- 框架介绍thinkphp
ThinkPHP是一个免费开源的,快速.简单的面向对象的 轻量级PHP开发框架 ,创立于2006年初,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而诞生的.ThinkPH ...
- Java打jar包详细教学
如果我们需要将写好并测试OK的公共接口供多个项目使用,我们可以不用拷贝源代码,可以编译后打包成jar文件,这样会很方便许多,修改的话也方便,直接修改源代码打一个新jar包替换即可,下面是打包的详细教程 ...
- 17.iOS App设置icon,启动图,App名称的方法
icon:选择Assets-->AppIcon-->将各种尺寸的icon拖拽到相应的框中. APP名称:选择info-->Bundle name,修改APP名字. 启动图: 首先点击 ...
- 开启Python之路
开始自学Python 环境配置 自己百度去!!! 计算与变量 字符创.列表.元组和字典 简单的画图 使用if和else条件控制语句 循环 使用函数和模块来重用代码 使用类和对象 Python内建函数的 ...
- Linux三剑客之sed
sed sed对文本的处理很强大,并且sed非常小,参数少,容易掌握,他的操作方式根awk有点像.sed按顺序逐行读取文件.然后,它执行为该行指定的所有操作,并在完成请求的修改之后的内容显示出来,也可 ...