2021-10-16 12:50

週期性執行的子執行緒範本

關於週期性執行的子執行緒有幾個要點:

  • 單次 Sleep 的時間不要太久,會影響程式的關閉
  • 不可以用 SpinWait 來做程式暫停,要用 Sleep 來暫停,這樣才會釋放 CPU
  • Error log 要注意會重複出現相同的 error
  • 有排除重複 error 時,要記得加上[錯誤解除]的 log,這樣才能知道程式是否有回到正常執行
  • 要執行的程式邏輯移到一個 method 裡,這樣可以避免 return 造成的迴圈中斷,也能分離邏輯的關注點


週期小於 10 秒的範本

  1. private static readonly ILogger _log = LogManager.GetCurrentClassLogger(); 
  2.  
  3. private int _cycleMSec = 1000; 
  4. private bool _runFlag = false; 
  5. private string _prevError; 
  6.  
  7. public void Start() 
  8. { 
  9.    if (_runFlag) { return; } 
  10.    _runFlag = true; 
  11.  
  12.    var thread = new Thread(() => 
  13.    { 
  14.        while (_runFlag) 
  15.        { 
  16.            /* 先睡可以避免在程式啟動時過於忙碌 */ 
  17.            Thread.Sleep(_cycleMSec); 
  18.  
  19.            try 
  20.            { 
  21.                /* 要執行的程式邏輯 */ 
  22.                cycleHandler(); 
  23.                if (_prevError != null) { _log.Info("錯誤結束"); } 
  24.                _prevError = null; 
  25.            } 
  26.            catch (Exception ex) 
  27.            { 
  28.                /* 避免相同的錯誤一直被記錄 */ 
  29.                if (_prevError == ex.Message) { continue; } 
  30.  
  31.                _prevError = ex.Message; 
  32.                _log.Fatal(ex, "執行錯誤"); 
  33.            } 
  34.        } 
  35.    }); 
  36.  
  37.    thread.Start(); 
  38. } 
  39.  
  40. public void Stop() 
  41. { 
  42.    _runFlag = false; 
  43. } 
  44.  
  45.  
  46. private void cycleHandler() 
  47. { 
  48.    // 主要的邏輯程式寫在這裡 
  49. } 


週期大於 10 秒的範本

  1. private static readonly ILogger _log = LogManager.GetCurrentClassLogger(); 
  2.  
  3. private int _cycleSec = 30; 
  4. private bool _runFlag = false; 
  5. private string _prevError; 
  6. private DateTime _nextTime = DateTime.Now; 
  7.  
  8. public void Start() 
  9. { 
  10.    if (_runFlag) { return; } 
  11.    _runFlag = true; 
  12.  
  13.    var thread = new Thread(() => 
  14.    { 
  15.        while (_runFlag) 
  16.        { 
  17.            /* 先睡可以避免在程式啟動時過於忙碌 */ 
  18.            Thread.Sleep(1000); 
  19.  
  20.            /* 檢查是否符合執行時間 */ 
  21.            if (_nextTime > DateTime.Now) { continue; } 
  22.  
  23.            /* 更新下一次的執行時間 */ 
  24.            _nextTime = DateTime.Now.AddSeconds(_cycleSec); 
  25.  
  26.            try 
  27.            { 
  28.                /* 要執行的程式邏輯 */ 
  29.                cycleHandler(); 
  30.                if (_prevError != null) { _log.Info("錯誤結束"); } 
  31.                _prevError = null; 
  32.            } 
  33.            catch (Exception ex) 
  34.            { 
  35.                /* 避免相同的錯誤一直被記錄 */ 
  36.                if (_prevError == ex.Message) { continue; } 
  37.  
  38.                _prevError = ex.Message; 
  39.                _log.Fatal(ex, "執行錯誤"); 
  40.            } 
  41.        } 
  42.    }); 
  43.  
  44.    thread.Start(); 
  45. } 
  46.  
  47. public void Stop() 
  48. { 
  49.    _runFlag = false; 
  50. } 
  51.  
  52.  
  53. private void cycleHandler() 
  54. { 
  55.    // 主要的邏輯程式寫在這裡 
  56. } 


停啟頻繁的範本

  1. public enum CycleStatus 
  2. { 
  3.    Stop, 
  4.    Start, 
  5.    Stoping, 
  6. } 
  7.  
  8. public CycleStatus RunStatus { get; private set; } = CycleStatus.Stop; 
  9.  
  10.  
  11. private static readonly ILogger _log = LogManager.GetCurrentClassLogger(); 
  12. private int _cycleMSec = 1000; 
  13. private string _prevError; 
  14.  
  15.  
  16. public void Start() 
  17. { 
  18.    if (RunStatus != CycleStatus.Stop) 
  19.    { throw new Exception("程序還在進行中"); } 
  20.  
  21.    RunStatus = CycleStatus.Start; 
  22.  
  23.    var thread = new Thread(() => 
  24.    { 
  25.        while (RunStatus == CycleStatus.Start) 
  26.        { 
  27.            /* 先睡可以避免在程式啟動時過於忙碌 */ 
  28.            Thread.Sleep(_cycleMSec); 
  29.  
  30.            try 
  31.            { 
  32.                /* 要執行的程式邏輯 */ 
  33.                cycleHandler(); 
  34.                if (_prevError != null) { _log.Info("錯誤結束"); } 
  35.                _prevError = null; 
  36.            } 
  37.            catch (Exception ex) 
  38.            { 
  39.                /* 避免相同的錯誤一直被記錄 */ 
  40.                if (_prevError == ex.Message) { continue; } 
  41.  
  42.                _prevError = ex.Message; 
  43.                _log.Fatal(ex, "執行錯誤"); 
  44.            } 
  45.        } 
  46.  
  47.        RunStatus = CycleStatus.Stop; 
  48.    }); 
  49.  
  50.    thread.Start(); 
  51. } 
  52.  
  53.  
  54. public void Stop() 
  55. { 
  56.    if (RunStatus == CycleStatus.Stop) 
  57.    { throw new Exception("程序已經停止"); } 
  58.  
  59.    if (RunStatus == CycleStatus.Stoping) 
  60.    { throw new Exception("程序正在停止"); } 
  61.  
  62.    RunStatus = CycleStatus.Stoping; 
  63. } 
  64.  
  65.  
  66. private void cycleHandler() 
  67. { 
  68.    // 主要的邏輯程式寫在這裡 
  69. } 

0 回應: