5、异步操作
5.1 异步操作基础
异步操作发展历史,APM模式,EAP模式,TPL模式
.NET 1.0
System.Threading.Thread
适用耗时操作、特殊操作、低优先级操作,默认前台
System.Threading.ThreadPool
适合短时操作,线程池线程默认后台
# APM 异步操作模式
.NET 2.0
Thread 构造支持 ParameterizedThreadStart 传参数
匿名方法 delegate,闭包
ParameterizedThreadStart start = delegate(object obj) { };
同步上下文 SynchronizationContext
主要用在桌面UI应用 Send(同步) or Post(异步)
# EAP 异步操作模式
.NET 3.5
拉姆达表达式
泛型委托 Action 无返回结果,Func 最后必须结果
Action a1 = new Action(() => { });
Action<string> a2 = new Action<string>((s) => { });
Func<string> f1 = new Func<string>(() => { return ""; });
Func<int, string> f2 = new Func<int, string>((n) => { return n.ToString(); });
.NET 4.0
线程池线程最大数量,是根据电脑内存来计算的
优化线程池工作项排序
在 .net 4.0 以前,线程池的工作项,采用链表排队
现在CPU都是多核处理器,假设现在有很多工作项
出现的问题:
(1)链表结构会存在很多引用,对垃圾回收影响很大
(2)链表是按顺序操作,多核CPU真正的并发受到影响
在 .net 4.0 重新设计工作项排队结构
数组+链表
数组元素对应工作项引用
(1)引用减少了
(2)现在是操作数组元素
# TPL 异步操作模式
5.2 异步操作模式
(1)APM 模式 Asynchronous Programming Model
2个方法 Begin/End,1个 IAsyncResult
必须调用 End,即使不需要返回结果,因为 End 会把线程的异常抛出来
调用 End 加 try/catch
调用 Begin 之后,应当避免直接调用 End,因为 End 会等待结果,可能无限等待
APM 获取结果
(1)轮询是否完成
主要使用 System.Windows.Forms.Timer
轮询 IAsyncResult 的 IsCompleted,并调用 End 获取结果
(2)等待完成,IAsyncResult 的 AsyncWaitHandle 可以设置超时
直接调用 End,可能因为线程死锁等,无限等待
使用 AsyncWaitHandle 可以设置超时,但是超时了就不会调用 End
不调用 End 就意味着线程的,异常可能没捕获,资源可能泄露
所以 AsyncWaitHandle 并不完美
(3)完成时回调,AsyncCallback
这里有个问题,就是回调并不是在UI线程,如果要更新UI控件,那就不可以
static void Main(string[] args)
{
HelloDelegate helloDelegate = new HelloDelegate(Hello);
helloDelegate.BeginInvoke(Callback, helloDelegate);
Console.ReadLine();
}
static void Callback(IAsyncResult ar)
{
HelloDelegate helloDelegate = ar.AsyncState as HelloDelegate;
try
{
string s = helloDelegate.EndInvoke(ar);
Console.WriteLine(s);
}
catch (Exception) { }
}
static string Hello()
{
return "hello";
}
public delegate string HelloDelegate();
APM 其他事
.NET 框架的一些类已经实现了 APM 模式
例如:使用 I/O thread 的 WebRequest,Stream,Socket,SqlCommand,MessageQueue 等
委托内在支持 APM 模式,使用(worker thread)
(2)EAP 模式 Event-Based Asynchronous Pattern
1个异步Async方法,1个Completed事件
static void Main(string[] args)
{
WebClient webClient = new WebClient();
webClient.DownloadDataCompleted += delegate(object sender, DownloadDataCompletedEventArgs e)
{
try
{
byte[] result = e.Result;
}
catch (Exception) { }
};
webClient.DownloadDataAsync(new Uri(""));
}
在获取 Result 的时候, try/catch
EAP 有个问题,如果发起多个异步请求,在完成事件里,需要区分结果来自哪个异步操作呢
(3)TPL 模式 Task Parallel Library
基于 System.Threading.Tasks.Task
实现标准的取消线程,报告线程进度操作
Task 本质代表未来的操作
Task task = new Task(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
throw new Exception("error");
});
task.Start();
task.ContinueWith((t) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(t.Exception.InnerException.Message);
}, TaskContinuationOptions.OnlyOnFaulted);
Console.ReadLine();
网友评论