關於週期性執行的子執行緒有幾個要點:
- 單次 Sleep 的時間不要太久,會影響程式的關閉
- 不可以用 SpinWait 來做程式暫停,要用 Sleep 來暫停,這樣才會釋放 CPU
- Error log 要注意會重複出現相同的 error
- 有排除重複 error 時,要記得加上[錯誤解除]的 log,這樣才能知道程式是否有回到正常執行
- 要執行的程式邏輯移到一個 method 裡,這樣可以避免 return 造成的迴圈中斷,也能分離邏輯的關注點
週期小於 10 秒的範本
private static readonly ILogger _log = LogManager.GetCurrentClassLogger();
private int _cycleMSec = 1000;
private bool _runFlag = false;
private string _prevError;
public void Start()
{
if (_runFlag) { return; }
_runFlag = true;
var thread = new Thread(() =>
{
while (_runFlag)
{
/* 先睡可以避免在程式啟動時過於忙碌 */
Thread.Sleep(_cycleMSec);
try
{
/* 要執行的程式邏輯 */
cycleHandler();
if (_prevError != null) { _log.Info("錯誤結束"); }
_prevError = null;
}
catch (Exception ex)
{
/* 避免相同的錯誤一直被記錄 */
if (_prevError == ex.Message) { continue; }
_prevError = ex.Message;
_log.Fatal(ex, "執行錯誤");
}
}
});
thread.Start();
}
public void Stop()
{
_runFlag = false;
}
private void cycleHandler()
{
// 主要的邏輯程式寫在這裡
}
週期大於 10 秒的範本
private static readonly ILogger _log = LogManager.GetCurrentClassLogger();
private int _cycleSec = 30;
private bool _runFlag = false;
private string _prevError;
private DateTime _nextTime = DateTime.Now;
public void Start()
{
if (_runFlag) { return; }
_runFlag = true;
var thread = new Thread(() =>
{
while (_runFlag)
{
/* 先睡可以避免在程式啟動時過於忙碌 */
Thread.Sleep(1000);
/* 檢查是否符合執行時間 */
if (_nextTime > DateTime.Now) { continue; }
/* 更新下一次的執行時間 */
_nextTime = DateTime.Now.AddSeconds(_cycleSec);
try
{
/* 要執行的程式邏輯 */
cycleHandler();
if (_prevError != null) { _log.Info("錯誤結束"); }
_prevError = null;
}
catch (Exception ex)
{
/* 避免相同的錯誤一直被記錄 */
if (_prevError == ex.Message) { continue; }
_prevError = ex.Message;
_log.Fatal(ex, "執行錯誤");
}
}
});
thread.Start();
}
public void Stop()
{
_runFlag = false;
}
private void cycleHandler()
{
// 主要的邏輯程式寫在這裡
}
停啟頻繁的範本
public enum CycleStatus
{
Stop,
Start,
Stoping,
}
public CycleStatus RunStatus { get; private set; } = CycleStatus.Stop;
private static readonly ILogger _log = LogManager.GetCurrentClassLogger();
private int _cycleMSec = 1000;
private string _prevError;
public void Start()
{
if (RunStatus != CycleStatus.Stop)
{ throw new Exception("程序還在進行中"); }
RunStatus = CycleStatus.Start;
var thread = new Thread(() =>
{
while (RunStatus == CycleStatus.Start)
{
/* 先睡可以避免在程式啟動時過於忙碌 */
Thread.Sleep(_cycleMSec);
try
{
/* 要執行的程式邏輯 */
cycleHandler();
if (_prevError != null) { _log.Info("錯誤結束"); }
_prevError = null;
}
catch (Exception ex)
{
/* 避免相同的錯誤一直被記錄 */
if (_prevError == ex.Message) { continue; }
_prevError = ex.Message;
_log.Fatal(ex, "執行錯誤");
}
}
RunStatus = CycleStatus.Stop;
});
thread.Start();
}
public void Stop()
{
if (RunStatus == CycleStatus.Stop)
{ throw new Exception("程序已經停止"); }
if (RunStatus == CycleStatus.Stoping)
{ throw new Exception("程序正在停止"); }
RunStatus = CycleStatus.Stoping;
}
private void cycleHandler()
{
// 主要的邏輯程式寫在這裡
}
0 回應:
張貼留言