创建Task
//1. 使用Action Task task1 = new Task(newAction(printMessage)); // 使用匿名代理 Task task2 = new Task(delegate { printMessage(); }); // 使用Lambda Task task3 = new Task(() =>printMessage()); // 使用匿名代理 Task task4 = new Task(() => { printMessage(); });
还可以使用Factory.StartNew()创建Task,区别在于, Factory.StartNew()主要用于创建简单的,生命周期短的Task。无法Start()已经运行的Task,必须创建1个新Task实例然后Start。
同时运行多个Task,Task Scheduler来决定线程的分配以及Task运行时的顺序。
设置Task参数
Task task1 = newTask((msg)=>{ Console.WriteLine(msg); }, "Firsttask"); task1.Start(); Console.ReadLine();
传参,打印。
获取Task返回值
Task<int> task1 = new Task<int>(()=> { Thread.Sleep(3000); return 1; }); task1.Start(); Console.WriteLine("Result 1: {0}", task1.Result); //Threadblocked Task<int> task2 = new Task<int>(obj=> { Thread.Sleep(3000); return 2; }, 100); task2.Start(); Console.WriteLine("Result 2: {0}", task2.Result); Console.ReadLine();
在获取Task的Result时,会造成线程阻塞,对于上例来说,task1执行完毕时,Task2才开始执行。
取消Task
CancellationTokenSource tokenSource = new CancellationTokenSource(); CancellationToken token = tokenSource.Token; Task task = new Task(() => { for(int i = 0;i < 5; i++) { Thread.Sleep(1000); if(token.IsCancellationRequested) { Console.WriteLine("Task cancel detected"); throw new OperationCanceledException(token); } else{ Console.WriteLine("Int value {0}", i); } } },token); task.Start(); Console.WriteLine("Task started , Press enter to cancel task"); Console.ReadLine(); Console.WriteLine("Cancelling task"); tokenSource.Cancel();
先创建了1个TokenSource,将其中的Token传入Action中,在Action中每秒打印1个数字,直到取消Task时,打印并抛出OperationCaceledException。
对于多个Task的情形,还可以将同一个Token传入它们,就可以一次取消多个Task。
监控Task
CancellationTokenSource tokenSource = new CancellationTokenSource(); CancellationToken token = tokenSource.Token; Task task1 = new Task(() => { for(int i = 0;i < 5; i++) { if(token.IsCancellationRequested) { Console.WriteLine("Task cancel detected"); throw new OperationCanceledException(token); } else{ Console.WriteLine("Int value {0}", i); } Thread.Sleep(1000); } },token); task1.Start(); Console.WriteLine("Task1 started , Press enter to cancel task"); Task task2 = new Task(()=>{ Console.WriteLine("task2 : waiting for task 1 , maximum wait 3 seconds"); token.WaitHandle.WaitOne(3000); Console.WriteLine("execute task2"); }); task2.Start(); Console.ReadLine(); Console.WriteLine("Cancelling task"); tokenSource.Cancel();
在上例中,开启了两个Task,task2需要等待task1执行完毕或被取消才执行,最大等待时间为3秒。
组合取消Task
对于一些情形,会希望传递多个Token的组合,当任意1个Token 取消了Task,就执行取消:
CancellationTokenSource tokenSource1 = new CancellationTokenSource(); CancellationTokenSource tokenSource2 = new CancellationTokenSource(); CancellationTokenSource tokenSource3 = new CancellationTokenSource(); CancellationTokenSource compositeSource = CancellationTokenSource.CreateLinkedTokenSource( tokenSource1.Token,tokenSource2.Token, tokenSource3.Token); Task task = new Task(() => { Console.WriteLine("any 1 of 3 token canceled , it will cancel"); compositeSource.Token.WaitHandle.WaitOne(); Console.WriteLine("task canceled"); throw new OperationCanceledException(compositeSource.Token); },compositeSource.Token); task.Start(); Console.WriteLine("task started and waiting for cancel"); Thread.Sleep(1000); Console.WriteLine("token2 canceling"); tokenSource2.Cancel(); Console.ReadLine();
如上例代码所示,3个Token的组合被传入Task中,当Token2取消时,Task被取消,还可以将Token2改为Token1和Token3,不再一一演示。
如果需要在程序外部了解Task是否被Cancel,只需访问IsCanceled属性即可。
等待Task
有时需要在Task外部等待Task执行完毕,可以使用task.Wait()。以下为示例场景:
CancellationTokenSource tokenSource = new CancellationTokenSource(); CancellationTokentoken = tokenSource.Token; Task task = new Task(()=>{ Console.WriteLine("task : please wait me for 3 secs to complete in main thread"); for(var i = 0 ;i < 3; i++){ Thread.Sleep(1000); } Console.WriteLine("task: complete"); },token); task.Start(); Console.WriteLine("main thread: i do some other jobs..."); Thread.Sleep(1000); Console.WriteLine("main thread: i am ready to wait..."); task.Wait(1500); Console.WriteLine("main thread : i continue some other job...");
如上例所示,在Task要求主线程等待3秒,可在主线程中,最多只能等1.5秒,如果task没结束就直接继续主线程中任务的执行。
等待多个任务
在主线程中,需要等待多个线程都执行完毕的情况:
CancellationTokenSource tokenSource = new CancellationTokenSource(); CancellationToken token = tokenSource.Token; Task task1 = new Task(()=>{ Console.WriteLine("task1 : wait me , main thread"); for(vari = 0 ;i < 3; i++){ Console.WriteLine(string.Format("task1 : {0}/3 done",i+1)); Thread.Sleep(1000); } Console.WriteLine("task1: complete"); },token); task1.Start(); Task task2 = new Task(()=>{ Console.WriteLine("task2 : wait me , main thread"); for(var i = 0 ;i < 2; i++){ Console.WriteLine(string.Format("task2 : {0}/2 done",i+1)); Thread.Sleep(1000); } Console.WriteLine("task2: complete"); },token); task2.Start(); Console.WriteLine("main thread : waiting for task1 and task2"); Task.WaitAll(task1,task2); Console.WriteLine("main thread : continue my jobs...");
如果需要等待多个任务,任意1个完成就继续,只需将上述代码中的WaitAll改为WaitAny即可,参数一样。