原文:
一种延迟方法调用的实现
需求场景
最近遇到一种场景,需要延迟某个步骤的实现,以便在延迟的过程中能够及早处理,从而取消任务。 比如,现在的服务器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();
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 }
延迟的实现
主要是执行一个定时的任务,去检测被延迟的方法是否达到了超时的时间,如果达到,则执行该方法。另外,提供一个可供取消方法的函数。
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 }
测试
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 }
运行结果如下: