国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

為什么要放棄使用Thread.Sleep

2019-11-14 16:07:33
字體:
供稿:網(wǎng)友

前言

此文并不是說要完全放棄使用Thread.Sleep,而是要說明在符合哪些情況下使用!

場景

很多時候,我們會需要一個定時服務(wù)來處理業(yè)務(wù)。

但并不是死死的每隔N分鐘執(zhí)行一次那種,而是在一次處理完后,算好下一次處理的時間點。

當?shù)竭_此時間點,觸發(fā)程序重新開始執(zhí)行代碼。

 

普遍做法

  

普遍的情況下,都是使用while(true){Thread.Sleep()}來實現(xiàn),廢話不多話,看代碼版本1:

class PRogram    {        static void Main(string[] args)        {            var workLists = new List<string>() { "任務(wù)1", "任務(wù)2", "任務(wù)3", "任務(wù)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("開始執(zhí)行處理:{0}", taskType);            return true;        }        private static int GetTotalMillisecondsForNext()        {            //這里根據(jù)自己的業(yè)務(wù)來決定            return 2 * 1000;        }    }

 代碼簡單易懂。

 

分析

版本1中,循環(huán)強制創(chuàng)建線程,并使用System.Threading.Thread.Sleep(tim)來掛起線程,然后重新喚醒。

這種方式不好之處在于:占用系統(tǒng)線程資源,是一種浪費。如同占著茅坑不拉屎!線程是一種十分寶貴的資源,創(chuàng)建,銷毀,切換 都是相當耗性能的。

當Sleep的時候,就等于說:現(xiàn)在我不用,但是你也別想用。你要用?自己去Create一個。

有的人說,Sleep的時候 不占用CPU啊!對,是不占用CPU ,但是占著線程資源,阻礙系統(tǒng)的線程調(diào)度!

可以參考下這文章

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來改進我們的程序。當執(zhí)行處理業(yè)務(wù)的代碼時,首先把timer停止,處理完畢后,算好一次執(zhí)行的時間點,賦給timer并啟動,看代碼版本2

class Program    {        static void Main(string[] args)        {            var workLists = new List<string>() { "任務(wù)1", "任務(wù)2", "任務(wù)3", "任務(wù)4" };            Parallel.ForEach(workLists,                new ParallelOptions() { MaxDegreeOfParallelism = 3 },                (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 = 1000;            _workTimer.Elapsed += new ElapsedEventHandler(TimerHanlder);            _workTimer.Start();        }        private void TimerHanlder(object sender, ElapsedEventArgs e)        {            _workTimer.Stop();            var interval = 1 * 60 * 1000;//處理失敗,1分鐘后重試            var maxTimes = 5;            var retryTimes = 0;            while (retryTimes < maxTimes)            {                var ok = Proccess();                if (ok)                {                    retryTimes = maxTimes;                }                else                {                    retryTimes++;                    System.Threading.Thread.Sleep(interval);                }            }            var times = GetTotalSecondsForNext();            Console.WriteLine("{0}秒后重新執(zhí)行", times);            _workTimer.Interval = times * 1000;//計算離下一次開始處理的時間            _workTimer.Start();        }        private bool Proccess()        {            Console.WriteLine("開始執(zhí)行處理:{0}", TaskType);            return true;        }        private int GetTotalSecondsForNext()        {            //這里根據(jù)自己的業(yè)務(wù)來決定            return 3;        }    }

特別說明一下:Main方法中的Console.ReadLine();很重要,讓主線程處于等待的狀態(tài),子線程就可以一直執(zhí)行下去不中斷

總結(jié)

1:使用Task,而不是使用new System.Threading.Thread。是否要創(chuàng)建線程,應(yīng)該讓系統(tǒng)來決定,利用可復(fù)用資源

2: System.Threading.Thread.Sleep(interval);只合適在 "有限度的 " 循環(huán)場景中,比如 最多重試N次、倒計時等等

 

 

如果不對之處,請各位斧正!

 


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 彭泽县| 尉犁县| 平山县| 类乌齐县| 时尚| 达州市| 康保县| 镇康县| 蒙城县| 松滋市| 京山县| 平度市| 闵行区| 明光市| 德惠市| 玛沁县| 阜康市| 石城县| 阿克| 水城县| 白水县| 中山市| 文昌市| 凌海市| 剑川县| 娄烦县| 汝阳县| 湟源县| 定兴县| 华安县| 胶州市| 都昌县| 巴林右旗| 土默特右旗| 连山| 佛冈县| 吐鲁番市| 射阳县| 遵义县| 阿瓦提县| 南丰县|