TPL Part 1 Task 的使用
创建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即可,参数一样。