.NET常见的异步编程模式分为:
APM(Asynchronous Programming Model) 异步编程模型
EAP(Event-based Asynchronous Pattern) 事件异步模式
TAP(Task-based Asynchronous Pattern) 任务异步模式
TPL(Task Parallel Pattern) 任务并行 模式
1.APM 异步编程模型
APM异步编程 通过begin 和end方法来操作,代指异步编程的开始和结束,下面通过几种异步模型来说明APM的执行
Deletegate 的异步执行
static void Main() { Handler handler =Test;//代理指针 Console.WriteLine("Invoke begin!"); var tmp= handler.BeginInvoke("test", new AsyncCallback(ar =>//代理的执行 { Console.WriteLine(ar.IsCompleted); handler.EndInvoke(ar);//结束代理 Console.WriteLine("Invoke end!"); }), null); Console.WriteLine("Main Thread"); Console.Read(); } public delegate void Handler(string name);//定义代理 public static void Test(string name) { Console.WriteLine("the arg is:{0}", name); }
执行结果:
可以看到,代理的异步执行并没有阻塞主线程,而是并行执行,代理的
BeginInvoke(string name,AsyncCallBack callback,object obj)
EndInvoke(IAsyncResult)
这是异步执行的两个方法,AsyncCallBack 是回调方法,name是传入方法的参数。IAsyncResult 定义如下:
public interface IAsyncResult { bool IsCompleted { get; } WaitHandle AsyncWaitHandle { get; } object AsyncState { get; } bool CompletedSynchronously { get; } }
IsCompleted 异步线程是否结束,当用同步方式执行异步代理的时候可以用此属性来查询异步代理是否结束
AsyncWaitHandle 获取一个信号量,等待异步的执行完毕
AsyncState 传入的状态量
WindowForm的控件操作
在UI编程中,所有的UI操作,包括修改UI的属性如显示文本,颜色,样式等 都必须在UI线程上操作,但是编程过程中,经常使用多线程编程,在我们自己定义的线程中直接访问UI控件的属性或者修改UI控件的属性的时候,通常是不安全的
多线程访问窗口中的控件,可以在窗口的构造函数中将Form的CheckForIllegalCrossThreadCalls静态属性设置为false,但是不推荐这种操作。
安全访问的方式:把自己定义的线程中UI操作放到UI线程上操作,这样就不会再有不安全的操作;
Control类的 Invoke,BeginInvoke 内部实现如下:
a) Invoke (同步调用)先判断控件创建线程与当前线程是否相同,相同则直接调用委托方法;否则使用Win32API的PostMessage 异步执行,但是 Invoke 内部会调用IAsyncResult.AsyncWaitHandle等待执行完成。
b) BeginInvoke (异步调用)使用Win32API的PostMessage 异步执行,并且返回 IAsyncResult 对象。
2) InvokeRequired
获取一个值,该值指示调用线程是否与控件的创建线程相同。
public Form1() { InitializeComponent(); if (this.InvokeRequired) { this.Invoke(new Action<String>(ChangeText), "test"); } else { ChangeText("test"); } } private void ChangeText(String str) { this.Text += str; }
2.EAP 基于事件的异步编程
事件模型的异步编程,大家都是很熟悉的,特别是在UI编程中 VS做的很好,只需要 双击下控件,IDE就自动为控件注册事件,当然也可以定义自己的事件:
1 public Form1() 2 { 3 InitializeComponent(); 4 this.NotifyEvent += () => { 5 Console.WriteLine("Event has been fired"); 6 }; 7 8 } 9 public event NotifyHandler NotifyEvent; 10 public delegate void NotifyHandler(); 11 public void OnNotify() 12 { 13 NotifyEvent?.Invoke(); 14 } 15 16 public void TestEvent() 17 { 18 OnNotify(); 19 } 20 21 private void button1_Click(object sender, EventArgs e) 22 { 23 TestEvent(); 24 }
点击按钮之后,就可以触发事件了