需求場景
最近遇到一種場景,需要延遲某個步驟的實現,以便在延遲的過程中能夠及早處理,從而取消任務。 比如,現在的服務器CPU過高了,則系統記錄下來,然后開始發送郵件通知用戶,但是如果在10秒之內CPU恢復了;或者我不希望用戶得知這個CPU的信息,因為我就在現場,我可以及時知道怎么處理這種情況,這個時候准備撥打電話的這個方法的調用就不能被執行,需要延遲一段時間,以便能夠被取消——以上場景僅供參考。
代碼實現
以下是我的一個實現方式,供大家討論,或者有更好的方式可以改進。
這種方法旨在能夠方便的延遲任意方法的執行:
定義任務接口
這是一個基本的線程任務的接口,包括任務名稱、線程的運行狀態、啟停線程。
1
interface ITask
2 {
3 string Name { get; }
4 bool IsRunning { get; }
5 void Start();
6 void Stop();
7 void Run();
2 {
3 string Name { get; }
4 bool IsRunning { get; }
5 void Start();
6 void Stop();
7 void Run();
8 }
定義延遲的信息類
保存當前需要延遲的方法,以及需要延遲的時間等
1 class LazyItem
2 {
3 private readonly int _timeout;
4 private readonly DateTime _enqueueTime;
5
6 public bool IsTimeout
7 {
8 get { return (DateTime.Now - _enqueueTime).TotalSeconds > _timeout; }
9 }
10 public string Key { get; private set; }
11 public Action Continue { get; private set; }
12
13 public LazyItem( string key, int timeout, Action continueAction)
14 {
15 _enqueueTime = DateTime.Now;
16 _timeout = timeout;
17 Key = key;
18 Continue = continueAction;
19 }
20 }
3 private readonly int _timeout;
4 private readonly DateTime _enqueueTime;
5
6 public bool IsTimeout
7 {
8 get { return (DateTime.Now - _enqueueTime).TotalSeconds > _timeout; }
9 }
10 public string Key { get; private set; }
11 public Action Continue { get; private set; }
12
13 public LazyItem( string key, int timeout, Action continueAction)
14 {
15 _enqueueTime = DateTime.Now;
16 _timeout = timeout;
17 Key = key;
18 Continue = continueAction;
19 }
20 }
延遲的實現
主要是執行一個定時的任務,去檢測被延遲的方法是否達到了超時的時間,如果達到,則執行該方法。另外,提供一個可供取消方法的函數。
1 class LazyInvoker : ITask
2 {
3 public string Name
4 {
5 get { return " Lazy Invoke Task "; }
6 }
7
8 public bool IsRunning { get; private set; }
9
10 private readonly ConcurrentDictionary< string, LazyItem> _lazyActions = new ConcurrentDictionary< string, LazyItem>();
11
12 public void Start()
13 {
14 Task.Factory.StartNew(Run);
15 IsRunning = true;
16 }
17
18 public void Stop()
19 {
20 IsRunning = false;
21 }
22
23 /// <summary>
24 /// 檢測被延遲的任務,達到超時時間則觸發
25 /// </summary>
26 /// Created by:marvin(2014/10/11 12:14)
27 public void Run()
28 {
29 while (IsRunning)
30 {
31 CheckContinue();
32 Thread.Sleep( 1 * 1000);
33 }
34 }
35
36 private void CheckContinue()
37 {
38 if (_lazyActions.Count <= 0) return;
39
40 var removeKeys = ( from lazyItem in _lazyActions where lazyItem.Value.IsTimeout select lazyItem.Key).ToList();
41 if (removeKeys.Count <= 0) return;
42
43 foreach ( var key in removeKeys)
44 {
45 LazyItem tmp;
46 if (_lazyActions.TryRemove(key, out tmp))
47 {
48 tmp.Continue();
49 }
50 }
51 }
52
53 /// <summary>
54 /// 延遲工作
55 /// </summary>
56 /// <param name="id"> The identifier. </param>
57 /// <param name="lazyTimeout"> The lazy timeout. </param>
58 /// <param name="continueAction"> The continue action. </param>
59 /// Created by:marvin(2014/10/11 11:48)
60 public void LazyDo( string id, int lazyTimeout, Action continueAction)
61 {
62 if (!_lazyActions.ContainsKey(id))
63 {
64 if (_lazyActions.TryAdd(id, new LazyItem(id, lazyTimeout, continueAction)))
65 {
66 // Console.WriteLine("lazy action : {0} , timeout : {1}", id, lazyTimeout);
67 }
68 }
69 }
70
71 /// <summary>
72 /// 取消任務
73 /// </summary>
74 /// <param name="actionKey"> The action key. </param>
75 /// Created by:marvin(2014/10/11 12:02)
76 public void Cancel( string actionKey)
77 {
78 if (_lazyActions.ContainsKey(actionKey))
79 {
80 LazyItem tmp;
81 if (_lazyActions.TryRemove(actionKey, out tmp))
82 {
83 Console.WriteLine( " lazy action “{0}” had removed ", tmp.Key);
84 }
85 }
86 }
87 }
3 public string Name
4 {
5 get { return " Lazy Invoke Task "; }
6 }
7
8 public bool IsRunning { get; private set; }
9
10 private readonly ConcurrentDictionary< string, LazyItem> _lazyActions = new ConcurrentDictionary< string, LazyItem>();
11
12 public void Start()
13 {
14 Task.Factory.StartNew(Run);
15 IsRunning = true;
16 }
17
18 public void Stop()
19 {
20 IsRunning = false;
21 }
22
23 /// <summary>
24 /// 檢測被延遲的任務,達到超時時間則觸發
25 /// </summary>
26 /// Created by:marvin(2014/10/11 12:14)
27 public void Run()
28 {
29 while (IsRunning)
30 {
31 CheckContinue();
32 Thread.Sleep( 1 * 1000);
33 }
34 }
35
36 private void CheckContinue()
37 {
38 if (_lazyActions.Count <= 0) return;
39
40 var removeKeys = ( from lazyItem in _lazyActions where lazyItem.Value.IsTimeout select lazyItem.Key).ToList();
41 if (removeKeys.Count <= 0) return;
42
43 foreach ( var key in removeKeys)
44 {
45 LazyItem tmp;
46 if (_lazyActions.TryRemove(key, out tmp))
47 {
48 tmp.Continue();
49 }
50 }
51 }
52
53 /// <summary>
54 /// 延遲工作
55 /// </summary>
56 /// <param name="id"> The identifier. </param>
57 /// <param name="lazyTimeout"> The lazy timeout. </param>
58 /// <param name="continueAction"> The continue action. </param>
59 /// Created by:marvin(2014/10/11 11:48)
60 public void LazyDo( string id, int lazyTimeout, Action continueAction)
61 {
62 if (!_lazyActions.ContainsKey(id))
63 {
64 if (_lazyActions.TryAdd(id, new LazyItem(id, lazyTimeout, continueAction)))
65 {
66 // Console.WriteLine("lazy action : {0} , timeout : {1}", id, lazyTimeout);
67 }
68 }
69 }
70
71 /// <summary>
72 /// 取消任務
73 /// </summary>
74 /// <param name="actionKey"> The action key. </param>
75 /// Created by:marvin(2014/10/11 12:02)
76 public void Cancel( string actionKey)
77 {
78 if (_lazyActions.ContainsKey(actionKey))
79 {
80 LazyItem tmp;
81 if (_lazyActions.TryRemove(actionKey, out tmp))
82 {
83 Console.WriteLine( " lazy action “{0}” had removed ", tmp.Key);
84 }
85 }
86 }
87 }
測試
1 class Program
2 {
3 static void Main( string[] args)
4 {
5 var lazyInvoker = new LazyInvoker();
6 lazyInvoker.Start();
7
8 // 延遲7秒運行
9 lazyInvoker.LazyDo(Guid.NewGuid().ToString(), 7, DoSomething);
10 Thread.Sleep( 5 * 1000);
11
12 // 延遲3秒運行,但是3秒的時候被取消
13 var id = Guid.NewGuid().ToString();
14 lazyInvoker.LazyDo(id, 5, DoSomething);
15 Thread.Sleep( 3 * 1000);
16 lazyInvoker.Cancel(id);
17
18 Console.ReadKey();
19 }
20
21 private static void DoSomething()
22 {
23 Console.WriteLine( " Now time is : " + DateTime.Now.ToString( " HH:mm:ss "));
24 }
25 }
3 static void Main( string[] args)
4 {
5 var lazyInvoker = new LazyInvoker();
6 lazyInvoker.Start();
7
8 // 延遲7秒運行
9 lazyInvoker.LazyDo(Guid.NewGuid().ToString(), 7, DoSomething);
10 Thread.Sleep( 5 * 1000);
11
12 // 延遲3秒運行,但是3秒的時候被取消
13 var id = Guid.NewGuid().ToString();
14 lazyInvoker.LazyDo(id, 5, DoSomething);
15 Thread.Sleep( 3 * 1000);
16 lazyInvoker.Cancel(id);
17
18 Console.ReadKey();
19 }
20
21 private static void DoSomething()
22 {
23 Console.WriteLine( " Now time is : " + DateTime.Now.ToString( " HH:mm:ss "));
24 }
25 }
運行結果如下:

