前言

EAP,全称Event-based Asynchronous Pattern,基于事件的异步模式,它提供了一系列的事件声明与方法,用于实现异步模式的各个阶段。

典型的内置组件为BackgroundWorker组件,本文中我们将使用它来探寻此种模式的执行过程。

异步模型

相较于APM的复杂性,基于事件异步编程(EAP)简化了编程,并可以方便得在异步方法过程中通过增加事件来回调,与主线程交互。

基于事件的异步模式的功能

  • 支持取消
  • 支持IsBusy属性
  • 支持完成通知
  • 支持进度报告
  • 支持返回增量结果

官方提供了AsyncCompletedEventArgsProgressChangedEventArgs等基础事件参数,可以直接使用或者继承使用,以及AsyncOperationAsyncOperationManager操作线程上下文的帮助类

官方给出一个简单的组件System.ComponentModel.BackgroundWorker

如何实现异步

  • [MethodName]Async
  • [MethodName]Completed
  • [MethodName]CancelAsync
  • EventArgs

命名规范

异步方法

对于同步方法创建对应的异步方法,以Async结尾。

1
2
3
4
5
6
7
8
9
10
11
//同步方法
public void Method(string param, object userState)
{
//do some thing
}

//异步方法
public void MethodAsync(string param, object userState)
{
//do some thing
}

异步完成方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//完成事件委托声明
public delegate void MethodCompletedEventHandler(object sender, MethodCompletedEventArgs e);

//完成事件参数类,继承自AsyncCompletedEventArgs,如果没有其它属性,直接父类本身即可
public class MethodCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
{
public MyReturnType Result { get; }
}

//对外提供完成事件绑定
public event MethodCompletedEventHandler MethodCompleted;


//通知外部绑定完成事件
public OnMethodCompleted(MethodCompletedEventArgs e)
{
if(MethodCompleted != null)
{
MethodCompleted(this,e)
}
}


进度更新和增量结果

通常以ProgressChanged结尾,ProgressChangedEventArgs是相对应得事件参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//更新事件处理委托声明
public delegate void ProgressChangedEventHandler(ProgressChangedEventArgs e);

//对外提供更新事件绑定
public event MethodProgressChangeEventHandler MethodProgressChanged;

//通知外部绑定更新事件
public OnMethodProgressChanged(ProgressChangedEventArgs e)
{
if(MethodProgressChanged != null)
{
MethodProgressChanged(e)
}
}

相对应的取消方法

1
2
3
4
5
6
7
8
9
10
11
//类中具有多个异步操作
public void MethodCancelAsync(object userState)
{
//do some thing
}

//整个类中具有一个异步操作
public void CancelAsync(object userState)
{
//do some thing
}

线程处理和上下文

同步方法最终是通过WorkerEventHandler委托方法执行,而委托底层是采用线程池来执行。方法执行完再用AsyncOperation通知主线程或UI线程

注意:.NET Core已经不支持委托异步调用,EAP底层由Task承接异步操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//通过委托来执行同步方法
private delegate void WorkerEventHandler(AsyncOperation asyncOp);

private SendOrPostCallback onProgressChangeDelegate = new SendOrPostCallback(MethodProgressChange);
private SendOrPostCallback onCompletedDelegate = new SendOrPostCallback(MethodComplete);

public void Method()
{
//do some thing
}

private void MethodWoker(AsyncOperation asyncOp)
{

Method();

//通过AsyncOperation.Post,触发更新异步传递主线程或UI线程
asyncOp.Post(this.onProgressChangeDelegate);

// do some thing

//执行完成后操作
this.CompletionMethod(asyncOp);
}

//触发当前线程更新事件,
private void MethodProgressChange(object state)
{
var e = state as ProgressChangedEventArgs;
OnMethodProgressChanged(e);
}

//异步后续完成逻辑
private void CompletionMethod(AsyncOperation asyncOp)
{
var e = new MethodCompletedEventArgs();
//由AsyncOperation完成后通知主线程或UI线程
asyncOp.PostOperationCompleted(onCompletedDelegate,e);
}

//触发当前线程完成事件
protected void MethodComplete(object operationState)
{
var e = operationState as MethodCompletedEventArgs
OnMethodCompleted(e);
}

public void MethodAsync()
{

//do some thing

AsyncOperation asyncOp = AsyncOperationManager.CreateOperation();

WorkerEventHandler work = new WorkerEventHandler(MethodWoker);

work.BeginInvoke(asyncOp);

//do some thing
}

小结

相较于APM的编程,EAP逻辑思维上更顺畅和丝滑,虽然底层都是用委托来实现异步,没有APM那么晦涩难懂,但是编码量还是不少。