总结

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: |||超大  

前言此文并不是说要完全放弃使用Thread.Sleep,而是要说明在符合哪些情况下使用!

场景很多时候,我们会需要一个定时服务来处理业务。

但并不是死死的每隔N分钟执行一次那种,而是在一次处理完后,算好下一次处理的时间点。

当到达此时间点,触发程序重新开始执行代码。

普遍做法

普遍的情况下,都是使用while(true){Thread.Sleep()}来实现,废话不多话,看代码版本1:

classPRogram

{

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

classProgram

{staticvoidMain(string[] args)

{varworkLists =newList<string>() {"任务1","任务2","任务3","任务4"};

Parallel.ForEach(workLists,newParallelOptions() { MaxDegreeOfParallelism =3},

(task)=> {newWork2() { TaskType =task }.DoWork(); });

Console.ReadLine();

}

}

classWork2

{privateTimer _workTimer;publicstringTaskType {get;set; }publicvoidDoWork()

{

_workTimer=newSystem.Timers.Timer();

_workTimer.Interval=1000;

_workTimer.Elapsed+=newElapsedEventHandler(TimerHanlder);

_workTimer.Start();

}privatevoidTimerHanlder(objectsender, ElapsedEventArgs e)

{

_workTimer.Stop();varinterval =1*60*1000;//处理失败,1分钟后重试varmaxTimes =5;varretryTimes =0;while(retryTimes <maxTimes)

{varok =Proccess();if(ok)

{

retryTimes=maxTimes;

}else{

retryTimes++;

System.Threading.Thread.Sleep(interval);

}

}vartimes =GetTotalSecondsForNext();

Console.WriteLine("{0}秒后重新执行", times);

_workTimer.Interval= times *1000;//计算离下一次开始处理的时间_workTimer.Start();

}privateboolProccess()

{

Console.WriteLine("开始执行处理:{0}", TaskType);returntrue;

}privateintGetTotalSecondsForNext()

{//这里根据自己的业务来决定return3;

}

}

特别说明一下:Main方法中的Console.ReadLine();很重要,让主线程处于等待的状态,子线程就可以一直执行下去不中断

总结1:使用Task,而不是使用new System.Threading.Thread。是否要创建线程,应该让系统来决定,利用可复用资源

2: System.Threading.Thread.Sleep(interval);只合适在 "有限度的 " 循环场景中,比如 最多重试N次、倒计时等等

如果不对之处,请各位斧正!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航