我们知道,每个应用程序就是一个进程,一个进程有多个线程。Task Parallel Library为我们的异步编程、多线程编程提供了强有力的支持,它允许一个主线程运行的同时,另外的一些线程或Task也同时运行。本篇体验基本用法。
基本用法
Taks的构造函数接收的类型是Action,也就是一个委托。
static void Main(string[] args) | |
{ | |
var t1 = new Task(() => | |
{ | |
Console.WriteLine("任务1开始"); | |
Thread.Sleep(1000); | |
Console.WriteLine("任务1结束"); | |
}); | |
t1.Start(); | |
Console.ReadKey(); | |
} |
如果把方法放到外面。
static void Main(string[] args) | |
{ | |
var t1 = new Task(() => DoSth(1,2000)); | |
t1.Start(); | |
Console.ReadKey(); | |
} | |
static void DoSth(int id, int sleepTime) | |
{ | |
Console.WriteLine("任务{0}开始",id); | |
Thread.Sleep(sleepTime); | |
Console.WriteLine("任务{0}结束",id); | |
} |
如果有多个Task同时执行。
static void Main(string[] args) | |
{ | |
var t1 = new Task(() => DoSth(1,2000)); | |
t1.Start(); | |
var t2 = new Task(() => DoSth(2, 1500)); | |
t2.Start(); | |
var t3 = new Task(() => DoSth(3, 3000)); | |
t3.Start(); | |
Console.ReadKey(); | |
} |
如果有很多Task,每个Task手动启动的话很费事,Task Parallel Library为我们准备了Task工厂。
static void Main(string[] args) | |
{ | |
var t1 = Task.Factory.StartNew(() => DoSth(1, 2000)); | |
var t2 = Task.Factory.StartNew(() => DoSth(2, 1500)); | |
var t3 = Task.Factory.StartNew(() => DoSth(3, 3000)); | |
Console.ReadKey(); | |
} |
如果我们想在一个任务结束之后立即执行某个任务,可以使用ContinueWith方法。
static void Main(string[] args) | |
{ | |
var t1 = Task.Factory.StartNew(() => DoSth(1, 2000)).ContinueWith((pre)=> DoOtherThing(4,2000)); | |
var t2 = Task.Factory.StartNew(() => DoSth(2, 1500)); | |
var t3 = Task.Factory.StartNew(() => DoSth(3, 3000)); | |
Console.ReadKey(); | |
} | |
static void DoSth(int id, int sleepTime) | |
{ | |
Console.WriteLine("任务{0}开始",id); | |
Thread.Sleep(sleepTime); | |
Console.WriteLine("任务{0}结束",id); | |
} | |
static void DoOtherThing(int id, int sleepTime) | |
{ | |
Console.WriteLine("其他任务{0}开始", id); | |
Thread.Sleep(sleepTime); | |
Console.WriteLine("其他任务{0}结束", id); | |
} |
如果希望等待所有的Task执行完毕,使用WaitAll方法。
static void Main(string[] args) | |
{ | |
var t1 = Task.Factory.StartNew(() => DoSth(1, 2000)); | |
var t2 = Task.Factory.StartNew(() => DoSth(2, 1500)); | |
var t3 = Task.Factory.StartNew(() => DoSth(3, 3000)); | |
var taskList = new List<Task> {t1, t2, t3}; | |
Task.WaitAll(taskList.ToArray()); | |
Console.WriteLine("我是在所有Task执行完毕后才执行的"); | |
Console.ReadKey(); | |
} |
如果想手动取消结束某个Task,需要为方法带上CancellationToken类型参数。
static void Main(string[] args) | |
{ | |
var source = new CancellationTokenSource(); | |
try | |
{ | |
var t1 = | |
Task.Factory.StartNew(() => DoSth(1, 1000, source.Token)) | |
.ContinueWith((pre) => DoOtherThing(2, 2000)); | |
source.Cancel(); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine(ex.GetType()); | |
} | |
Console.WriteLine("haha"); | |
Console.ReadKey(); | |
} | |
static void DoSth(int id, int sleepTime, CancellationToken token) | |
{ | |
if (token.IsCancellationRequested) | |
{ | |
Console.WriteLine("任务被取消"); | |
token.ThrowIfCancellationRequested(); | |
} | |
Console.WriteLine("任务{0}开始",id); | |
Thread.Sleep(sleepTime); | |
Console.WriteLine("任务{0}结束",id); | |
} | |
static void DoOtherThing(int id, int sleepTime) | |
{ | |
Console.WriteLine("其他任务{0}开始", id); | |
Thread.Sleep(sleepTime); | |
Console.WriteLine("其他任务{0}结束", id); | |
} |
如何从Task从获取方法的返回结果呢?
static void Main(string[] args) | |
{ | |
Console.WriteLine("开始计算"); | |
Task<int> t = Task.Factory.StartNew(() => Sum(1, 2)); | |
Console.WriteLine("等待结果"); | |
Console.WriteLine(t.Result); | |
Console.ReadKey(); | |
} | |
static int Sum(int a, int b) | |
{ | |
return a + b; | |
} |
后面一个Task获取前面一个Task的返回值。
static void Main(string[] args) | |
{ | |
Task<string> firstTask = Task.Factory.StartNew<string>(() => | |
{ | |
Console.WriteLine("第一个任务开始"); | |
return "hi from the one"; | |
}); | |
Task secondTask = firstTask.ContinueWith((prevoursTask) => | |
{ | |
Console.WriteLine("这里是第二个任务,获取到第一个任务的返回值是{0}",prevoursTask.Result,TaskContinuationOptions.OnlyOnRanToCompletion); | |
}); | |
secondTask.Wait(); | |
Console.ReadKey(); | |
} |
等待所有Task完成。
static void Main(string[] args) | |
{ | |
var t1 = Task.Factory.StartNew(() => | |
{ | |
Console.WriteLine("第一个任务"); | |
Thread.Sleep(1000); | |
}); | |
var t2 = Task.Factory.StartNew(() => | |
{ | |
Console.WriteLine("第二个任务"); | |
Thread.Sleep(1000); | |
}); | |
var taskList = new List<Task> {t1, t2}; | |
Task.Factory.ContinueWhenAll(taskList.ToArray(), (t) => { Console.WriteLine("所有任务完成我就出来"); }); | |
Console.ReadKey(); | |
} |
如果是嵌套Task。
static void Main(string[] args) | |
{ | |
Task.Factory.StartNew(() => | |
{ | |
Task child = Task.Factory.StartNew(() => | |
{ | |
Console.WriteLine("我是子任务"); | |
}, TaskCreationOptions.AttachedToParent); | |
}).Wait(); | |
Console.ReadKey(); | |
} |
启动Task的几种方式
1、通过Task.Factory.StartNew方法。
static void Main(string[] args) | |
{ | |
Task.Factory.StartNew(() => SaySth("hello")); | |
Console.ReadKey(); | |
} | |
static void SaySth(string msg) | |
{ | |
Console.WriteLine(msg); | |
} |
2、通过Task的Start实例方法
static void Main(string[] args) | |
{ | |
var t = new Task(() => SaySth("hello")); | |
t.Start(); | |
Console.ReadKey(); | |
} |
或者干脆用委托。
static void Main(string[] args) | |
{ | |
Task t = new Task(delegate {SaySth("hello");}); | |
t.Start(); | |
Console.ReadKey(); | |
} |
3、Task的静态方法Run
static void Main(string[] args) | |
{ | |
Task t = Task.Run(() => SaySth("hello")); | |
Console.ReadKey(); | |
} | |
static void SaySth(string msg) | |
{ | |
Console.WriteLine(msg); | |
} |
一个例子
比如说要下载某个页面,在保持当前UI界面无影响的情况下,使用Task在后台启动任务下载某个页面。
static void Main(string[] args) | |
{ | |
Console.WriteLine("界面内容"); | |
Task<string> r = DownloadAsync("http://www.baidu.com"); | |
while (!r.IsCompleted) | |
{ | |
Console.Write("."); | |
Thread.Sleep(250); | |
} | |
Console.WriteLine(r.Result); | |
Console.ReadKey(); | |
} | |
private static string DownloadWebPage(string url) | |
{ | |
WebRequest request = WebRequest.Create(url); | |
WebResponse response = request.GetResponse(); | |
var reader = new StreamReader(response.GetResponseStream()); | |
return reader.ReadToEnd(); | |
} | |
private static Task<string> DownloadAsync(string url) | |
{ | |
return Task.Factory.StartNew(() => DownloadWebPage(url)); | |
} |