-
Task类
- Task类:可以取代Thread类、ThreadPool类;
-Task.Run()
:异步执行委托; WaitAll(线程数组)
,阻塞主线程,等所有子线程执行完成以后,继续执行后面的代码;WaitAny(线程数组)
,阻塞主线程,等任意一个子线程执行完成以后,继续执行后面的代码;WhenAll(线程数组)
,不阻塞主线程,可与ContinueWith()结合使用,所有子线程执行完后,执行ContinueWith()
里的委托;WhenAny(线程数组)
,不阻塞主线程;task.ContinueWith(委托)
:task执行完以后回调委托,新线程执行这个回调委托;Task.Delay(1000)
和Thread.Sleep(1000)
区别:前者(Delay)时延迟,不阻塞线程,异步执行与ContinueWith()结合使用;- 泛型:
Task<T>
:即返回一个T类型对象的异步,执行的是Func;
-
TaskFactory
- 实例化后,调用
StartNew()
,可以传入委托以及state,一个由委托使用的只读对象,比如标识子线程; ContinueWhenAll()
:所有任务对象都已完成时,创建一个新的任务并执行与Task.WhenAll
方法 作用相当ContinueWhenAny()
:所有任务对象任何一个任务完成就创建一个新的任务并执行 与Task.WhenAny方法 作用相当
-
ManualResetEvent
- 这个一直不好理解的记忆,只能死记了;
ManualResetEvent
的构造方法有个bool型参数,当为true时,子线程调用WaitOne()
方法不阻塞,当为false时,调用WaitOne()`方法就阻塞;WaitOne()
方法:调用此方法,会判断是否要阻塞;Set()
方法:设置不阻塞;Reset()
方法:设置阻塞;
-
CancellationTokenSource
- 线程是外部无法中止的,是由OS接管的,只能线程内部自行停止;
Cancel()
方法:取消线程,修改属性:IsCancellationRequested
为true
;Token
属性:如果在线程还未启动时,就传入Token属性且Cancel()
被调用了,那这个线程则会不启动,如果线程启动后再调用的Cancel()
则可以在线程内各逻辑处理前加IsCancellationRequested
的判断,或者还可以调用Token.ThrowIfCancellationRequested()
抛出异常;IsCancellationRequested
属性:是否取消线程;Token.Register(委托)
:注册一个委托,在调用Cancel()
后,即调用Cancel()
后会执行;
Parallel
- 并行编程,阻塞主线程,可以控制并发线程数量,传入参数:
new ParallelOptions().MaxDegreeOfParallelism=3
; Parallel.For()
:循环调用一个委托,state.Stop();return;
,结束此次Parallel,state.Breadk();return;
结束此线程;Parallel.ForEach()
:循环调用一个委托;
子线程异常处理建议
- 最佳处理:子线程内自行捕获异常,除非在主线程里用
WaitAll()
捕获子线程异常,否则自线程异常不会被主线程接受到,或者说主线程不知子线程里是否有异常发生; AggregateException
:多线程异常类,将多个线程的异常一起记录;
async await的理解
- 三要素:调用方法,异步方法(用async修饰),异步方法内一个或多个await(修饰任务),调用方法里调用异步方法;
- 在async/await修饰的异步方法里,主线程遇到
await
时,就会立即跳出方法,继续执行其他代码;同时await
后面的语句以及await
那句,由子线程(新线程)开始执行,await
那句执行完成后,此子线程继续将await
后面的代码段(还是方法内的)接力完成,因为主线程已跳出方法体,这样主线程不会被阻塞,除非要获取await
异步执行结果,比如用task.Result
或者task.Wait()
; await
修饰的一般是Task
或Task<T>
,如果是后者,则会返回T
类型的变量;await Task<T>
:可以理解为由子线程接管并执行,最后将T
类型变量返回出来,这样主线程不会被阻塞,除非要获取await
异步执行结果;- 异步方法里await后面的代码段相当于被当成task的回调方法,类似
ContinueWith(await后面的代码段)
; - 同步编程异步实现的理解:用了await\async,可以实现顺序执行,但不是由主线程执行到底,而是多个线程接力按顺序执行(在await处接力);
- 比如查违章,以往输入参数后并提交,主线程就循环+休眠的方法判断是否有返回结果了,但用async/await则可以按顺序执行,查违章以及返回的代码段写在await的task里,由一个子线程按顺序执行下去,省去循环判断以免阻塞主线程,最后子线程再将结果赋值给变量(或写入界面的文本框里);
- 微软建议异步方法的命名,是在方法名后添加Aysnc后缀;
- 用async,await来修饰一个方法,表明这个方法是异步的,声明的方法的返回类型必须为:void、Task、Task,最好不要是void;
- 被await修饰的只能是Task或者Task类型,通常情况下是一个返回类型是Task/Task的方法,当然也可以修饰一个Task/Task变量,await只能出现在已经用async关键字修饰的异步方法中。
-
- 异步方法返回值是Task的函数可以不用return;
BeginInvoke,EndInvoke
- BeginInvoke和EndInvoke是委托对象的2个方法,所以一个方法要实现BeginInvoke和EndInvoke方法,就必须用委托包一层且这个委托对象的调用列表只有一个方法;
- 有三种调用模式:
- 等待完成模式:调用委托对象(调用列表有个方法,或者方法被委托包了一层)的EndInvoke方法,会阻塞线程;
- 轮询模式:循环判断BeginInvoke返回对象的IsCompleted,会阻塞线程;
- 回调模式:用BeginInvoke方法的最后2个参数,倒数第2个是回调方法,最后1个参数是回调方法的参数,通常把委托对象(有异步方法的引用)作为参数,回调方法由异步线程执行,即新线程先执行完BeginInvoke,再接着执行EndInvoke;
- EndInvoke的作用:取异步方法的执行结果(可能会阻塞线程)以及释放异步方法的资源,参数则是BeginInvoke返回的结果;
- IAsyncResult:BeginInvoke方法创建的是AsyncResult对象,但实际上只返回了这个对象里的一部分(即实现了IAsyncResult接口的部分),AsyncDelegate属性,就没在接口里;

delegate int SumDelegate(int x, int y);
static void Main(string[] args)
{
SumDelegate sumDelegate = new SumDelegate(sum);
IAsyncResult async= sumDelegate.BeginInvoke(5, 10, null, null);
int s= sumDelegate.EndInvoke(async);
Console.WriteLine($"Main Thread ID:{Thread.CurrentThread.ManagedThreadId},结果:{s}");
Console.ReadKey();
}
static int sum(int x,int y)
{
Console.WriteLine($"Thread ID:{Thread.CurrentThread.ManagedThreadId} sum方法");
Thread.Sleep(3000);
int s = x + y;
return s;
}
delegate int SumDelegate(int x, int y);
static void Main(string[] args)
{
SumDelegate sumDelegate = new SumDelegate(sum);
IAsyncResult async = sumDelegate.BeginInvoke(5, 10, null, null);
while (!async.IsCompleted)
{
Console.WriteLine("sum方法,还未执行完成...");
Thread.Sleep(500);
}
int s = sumDelegate.EndInvoke(async);
Console.WriteLine($"Main Thread ID:{Thread.CurrentThread.ManagedThreadId},结果:{s}");
Console.ReadKey();
}
static int sum(int x, int y)
{
Console.WriteLine($"Thread ID:{Thread.CurrentThread.ManagedThreadId} sum方法开始");
Thread.Sleep(3000);
int s = x + y;
return s;
}
delegate int SumDelegate(int x, int y);
static void Main(string[] args)
{
SumDelegate sumDelegate = new SumDelegate(sum);
IAsyncResult async = sumDelegate.BeginInvoke(5, 10
, new AsyncCallback((r) =>
{
int re = ((SumDelegate)r.AsyncState).EndInvoke(r);
Console.WriteLine($"回调方法里的EndInvoke结果:{re}");
})
, sumDelegate);
Console.ReadKey();
}
static int sum(int x, int y)
{
Console.WriteLine($"Thread ID:{Thread.CurrentThread.ManagedThreadId} sum方法开始");
Thread.Sleep(3000);
int s = x + y;
return s;
}