C#多线程之线程基础篇( 五 )


APM是建立在委托之上的,Net Core中的委托 不支持异步调用,也就是 BeginInvoke 和 EndInvoke 方法 。
void APM(){var uri = new Uri("https://www.albahari.com/threading/part3.aspx");Func<Uri, int> f = CalcUriStringCount;var res = f.BeginInvoke(uri, null, null);// do something_testOutputHelper.WriteLine("我可以做别的事情");_testOutputHelper.WriteLine("共下载字符数:" + f.EndInvoke(res));}int CalcUriStringCount(Uri uri){var client = new WebClient();var res = client.DownloadString(uri);return res.Length;}EndInvoke会做三件事:

  1. 如果异步委托还没有结束,它会等待异步委托执行完成 。
  2. 它会接收返回值(也包括refout方式的参数) 。
  3. 它会向调用线程抛出未处理的异常 。
不要因为异步委托调用的方法没有返回值就不调用EndInvoke,因为这将导致其内部的异常无法被调用线程察觉 。MSDN文档中明确写了 “无论您使用何种方法,都要调用 EndInvoke 来完成异步调用 。”
BeginInvoke也可以指定一个回调委托 。这是一个在完成时会被自动调用的、接受IAsyncResult对象的方法 。
BeginInvoke的最后一个参数是一个用户状态对象,用于设置IAsyncResultAsyncState属性 。它可以是需要的任何东西,在这个例子中,我们用它向回调方法传递method委托,这样才能够在它上面调用EndInvoke
var uri = new Uri("https://www.albahari.com/threading/part3.aspx");Func<Uri, int> func = CalcUriStringCount;var res = func.BeginInvoke(uri, new AsyncCallback(res =>{var target = res.AsyncState as Func<string, int>;_testOutputHelper.WriteLine("共下载字符数:" + target!.EndInvoke(res));_testOutputHelper.WriteLine("异步状态:" + res.AsyncState);}), func);// do something_testOutputHelper.WriteLine("我可以做别的事情");func.EndInvoke(res);基于事件的异步模式(EAP)基于事件的异步模式(event-based asynchronous pattern),EAP 是在 .NET Framework 2.0 中提出的,让类可以提供多线程的能力,而不需要使用者显式启动和管理线程 。这种模式具有以下能力:
  • 协作取消模型(cooperative cancellation model)
  • 线程亲和性(thread affinity)
  • 将异常转发到完成事件(forwarding exceptions)
这个模式本质上就是:类提供一组成员,用于在内部管理多线程,类似于下边的代码:
// 这些成员来自于 WebClient 类:public byte[] DownloadData (Uri address);// 同步版本public void DownloadDataAsync (Uri address);public void DownloadDataAsync (Uri address, object userToken);public event DownloadDataCompletedEventHandler DownloadDataCompleted;public void CancelAsync (object userState);// 取消一个操作public bool IsBusy { get; }// 指示是否仍在运行当调用基于EAP模式的类的XXXAsync方法时,就开始了一个异步操作,EAP模式是基于APM模式之上的 。
var client = new WebClient();client.DownloadStringCompleted += (sender, args) =>{if (args.Cancelled) _testOutputHelper.WriteLine("已取消");else if (args.Error != null) _testOutputHelper.WriteLine("发生异常:" + args.Error.Message);else{_testOutputHelper.WriteLine("共下载字符数:" + args.Result.Length);// 可以在这里更新UI 。。}};_testOutputHelper.WriteLine("我在做别的事情");client.DownloadStringAsync(new Uri("https://www.albahari.com/threading/part3.aspx"));BackgroundWorker是命名空间System.ComponentModel中的一个工具类,用于管理工作线程 。它可以被认为是一个 EAP 的通用实现,在EAP功能的基础上额外提供了: