微软docs参考:
https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/calling-synchronous-methods-asynchronously
也可参考:http://www.cnblogs.com/sosowjb/archive/2012/08/11/2633953.html 写得也很好.
异步委托:异步委托就是定义一个方法,开一个新线程,让这个方法在后台执行.这个线程是线程池里的线程,是属于后台线程的。
Delegate类提供了BeginInvoke()异步委托方法,如果是非常耗时的异步操作,那麼在未结束时调用Delegate.EndInvoke()会一直处在阻塞状态。可通過以下3種方法判斷是否完成。
1)BeginInvoke()返回一个IAsyncResult接口,这个接口包含了该委托的相关信息,并且可以通过它的用IsCompleted属性来判断该委托是否执行完成。
2) 等待句柄(AsyncWaitHandle属性)
3) 异步回调(AsyncCallBack委托)—推薦
下面是将要异步调用的方法:模拟 n 毫秒后执行完毕.
1: static string DelegateMethod(int ms)
2: {
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记线程ID
3: Console.WriteLine("Takes started");
4: Thread.Sleep(ms);
5: Console.WriteLine("Takes completed");
6: return "Done!";
7: }
**方法1:用IsCompleted属性判断是否完成。**如果没完成则继续等待,如果完成则跳出循环。用EndInvoke方法获取委托的返回值。如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕。
主线程的方法:
首先定义一个委托:
public delegate string MyDelegate(int ms);
1: static void Main()
2: {
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主线程ID
3: MyDelegate dl = DelegateMethod;
4:
5: IAsyncResult ar = dl.BeginInvoke(5000, null, null); --5000是委托方法DelegateMethod的参数,另两个参数是默认的
6:
7: while (!ar.IsCompleted)
8: {
9: Console.Write("waiting");
10: Thread.Sleep(50);
11: }
12: string result = dl.EndInvoke(ar); --
13: Console.WriteLine("result: {0}", result);
14: }
委托线程将执行5秒钟,主线程不停的循环判断委托线程是否完成(用IsCompleted属性判断)。如果没完成则继续等待,如果完成则跳出循环。用EndInvoke方法获取委托的返回值。如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕。
方法2:等待句柄(AsyncWaitHandle属性)
使用IAsyncResult的AsyncWaitHandle属性可以访问等待句柄,这个属性返回一个WaitHandle对象,这个对象的WaitOne()方法可输入一个超时时间作为参数,设置等待的最长时间。如果超时,WaitOne()方法返回一个bool值,true为等待成功(即委托完成),异步调用的方法与上面一样,
主线程实现:
1: static void Main()
2: {
3: MyDelegate dl = DelegateMethod;
4:
5: IAsyncResult ar = dl.BeginInvoke(5000, null, null);
6: while (true)
7: {
8: Console.Write("waiting");
9: if (ar.AsyncWaitHandle.WaitOne(50))
10: {
11: Console.WriteLine("Can get the result now");
12: break;
13: }
14: }
15: string result = dl.EndInvoke(ar);
16: Console.WriteLine("result: {0}", result);
17: }
主线程每等待50秒做一次判断是否完成。
方法3:异步回调(AsyncCallBack委托)–個人推薦這種方法,不會阻塞后面的語句
BeginInvoke方法第二个参数可传入一个AsnycCallBack委托类型的方法,当异步调用完成时会执行这个方法。可以用Lambda表达式或函數来实现:
MyDelegate dl = null;
static void Main()
{
dl = DelegateMethod;
dl.BeginInvoke(5000, new AsyncCallback(ar =>
{
//異步方法執行完成后執行以下代碼:
string result = dl.EndInvoke(ar);
Console.WriteLine("result: {0}", result);
}), null);
// 回調函數獨立封裝
// dl.BeginInvoke(5000, MyCallBack, null);
// 此處后面不發生阻塞
for (int i = 0; i < 100; i++)
{
Console.Write("waiting");
Thread.Sleep(50);
}
}
//回調函數
private void MyCallBack(IAsyncResult ar)
{
string result = dl.EndInvoke(ar);
Console.WriteLine("result: {0}", result);
}
BeginInvoke方法的最后一个参数可以用IAsyncResult的AsyncState属性获取。