.NET多线程(五)异步操作

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 a2 = new Action((s) => { });
Func f1 = new Func(() => { return ""; });
Func f2 = new Func((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();

你可能感兴趣的:(.NET多线程(五)异步操作)