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
会做三件事:
- 如果异步委托还没有结束,它会等待异步委托执行完成 。
- 它会接收返回值(也包括
ref
和out
方式的参数) 。 - 它会向调用线程抛出未处理的异常 。
不要因为异步委托调用的方法没有返回值就不调用EndInvoke,因为这将导致其内部的异常无法被调用线程察觉 。MSDN文档中明确写了 “无论您使用何种方法,都要调用 EndInvoke 来完成异步调用 。”
BeginInvoke
也可以指定一个回调委托 。这是一个在完成时会被自动调用的、接受IAsyncResult
对象的方法 。BeginInvoke
的最后一个参数是一个用户状态对象,用于设置IAsyncResult
的AsyncState
属性 。它可以是需要的任何东西,在这个例子中,我们用它向回调方法传递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功能的基础上额外提供了:- 报告工作进度的协议
- 实现了
IComponent
经验总结扩展阅读
- go GMP
- 豆腐在冷藏室可以放几天
- 200ml牛奶是多少克
- 一碗米饭的热量是多少
- 45岁男士体脂率多少正常 45岁男人体脂率多少
- 70多岁还能骑自行车吗 70岁老人能骑自行车吗
- 虾干热量有多少 虾干的热量是多少
- 一个水煮蛋多少大卡
- 板栗放冰箱里能存放多久
- 螃蟹干放着能活多久