Task
出现之前,微软的多线程处理方式有:Thread→ThreadPool→委托的异步调用
,虽然可以满足基本业务场景,但它们在多个线程的等待处理方面、资源占用方面、延续和阻塞方面都显得比较笨拙,在面对复杂的业务场景下,显得有点捉襟见肘.Net 4.0
时代推出来的,也是微软极力推荐的一种多线程的处理方式,Task
看起来像一个Thread
,实际上,它是在ThreadPool
的基础上进行的封装Task
的控制和扩展性很强,在线程的延续、阻塞、取消、超时等方面远胜于Thread
和ThreadPool
Task
可以简单看作相当于Thead
+TheadPool
,其性能比直接使用Thread
要更好,在工作中更多的是使用Task
来处理多线程任务Task跟Thread并不是一对一的关系。比如说开启10个任务并不一定会开启10个线程,因为使用Task开启新任务时,是从线程池中调用线程,这点与ThreadPool.QueueUserWorkItem类似
Task
对象后调用其 Start()
函数Task
的静态方法Run()
Task
工厂,新建一个线程// 方式一,通过Start
Task t1 = new Task(() => { Console.WriteLine("我是Task方式一"); });
t1.Start();
// 方式二,通过Run
Task t2= Task.Run(()=>{Console.WriteLine("我是Task方式二"); });
// 方式三,通过工厂
Task t3= Task.Factory.StartNew(()=>{Console.WriteLine("我是Task方式三"); });
static void Main()
{
// 没有返回参数
Task t1 = new Task(() => { Console.WriteLine("我是Task没有返回参数"); });
t1.Start();
// 有返回参数
Task t2 = new Task(() => { return 1+1; });
t2.Start();
int result = t2.Result;
Console.WriteLine(result);
}
输出结果
我是Task没有返回参数
2
static void test1()
{
Task[] taskArray = new Task[10];
for (int i = 0; i < 10; i++)
{
int bb = i;
Task t = Task.Run(() => { Console.WriteLine("任务ID:{0}, 结果:{1}",Thread.CurrentThread.ManagedThreadId, bb); });
taskArray[i] = t;
}
// 等待所有任务完成
Task.WaitAll(taskArray);
}
输出结果
任务ID:4, 结果:0
任务ID:10, 结果:4
任务ID:7, 结果:1
任务ID:8, 结果:2
任务ID:10, 结果:7
任务ID:11, 结果:5
任务ID:9, 结果:3
任务ID:12, 结果:6
任务ID:7, 结果:8
任务ID:8, 结果:9
Wait()
: 等待单个线程任务完成 WaitAll():
来指定等待的一个或多个线程结束WaitAny():
来指定等待任意一个线程任务结束static void test3()
{
// 方式一: wait方法
Task t = Task.Run(() => { Console.WriteLine("方式1:任务1......"); }) ;
// 等待 上述任务完成
t.Wait();
Console.WriteLine("方式一结束..........");
// 方式二: waitAll 方法
Task tt = Task.Run(() => { Console.WriteLine("方式2:任务1......"); });
Task tt2 = Task.Run(() => { Console.WriteLine("方式2:任务2......"); });
Task.WaitAll(tt,tt2);
Console.WriteLine("方式二结束..........");
// 方式三:waitAny 方法
Task ttt = Task.Run(() => { Console.WriteLine("方式3:任务1......"); });
Task ttt2 = Task.Run(() => { Console.WriteLine("方式3:任务2......"); });
Task.WaitAny(ttt, ttt2);
Console.WriteLine("方式三结束..........");
}
输出结果
方式1:任务1......
方式一结束..........
方式2:任务1......
方式2:任务2......
方式二结束..........
方式3:任务2......
方式3:任务1......
方式三结束..........
WhenAll()
中指定的线程任务完成后再执行ContinueWith()
中的任务,也就是线程任务的延续。而由于这个等待是异步的,因此不会给主线程造成阻塞static void test4()
{
Task t = Task.Run(() => { Thread.Sleep(1000); Console.WriteLine("我是线程任务....."); });
// 异步创建延续任务
Task.WhenAll(t).ContinueWith((data) => { Console.WriteLine("我是延续任务...."); });
Console.WriteLine("这是主线程........");
Console.ReadKey();
}
输出结果
这是主线程........
我是线程任务.....
我是延续任务....
注:Task任务的延续 与 上面阻塞相比,主要的好处就是 延续是异步的不会阻塞主线程
static void test5()
{
// 建立一个父任务
Task parentTask = new Task(() => {
// 创建两个子任务,依附在父任务上
Task.Factory.StartNew(() => { Console.WriteLine("子task1任务。。。。。。"); }, TaskCreationOptions.AttachedToParent);
Task.Factory.StartNew(() => { Console.WriteLine("子task2任务。。。。。。"); }, TaskCreationOptions.AttachedToParent);
Thread.Sleep(1000);
Console.WriteLine("我是父任务........");
});
parentTask.Start();
parentTask.Wait();
Console.WriteLine("这里是主线程.......");
Console.ReadKey();
}
输出结果
子task2任务。。。。。。
子task1任务。。。。。。
我是父任务........
这里是主线程.......
Task
中的取消功能使用的是CanclelationTokenSource
,即取消令牌源对象,可用于解决多线程任务中协作取消和超时取消static void test6()
{
// 情况一: 直接取消
// 创建取消令牌源对象
CancellationTokenSource cst = new CancellationTokenSource();
//第二个参数传入取消令牌
Task t = Task.Run(() => {
while (!cst.IsCancellationRequested)
{
Thread.Sleep(500);
Console.WriteLine("情况一,没有接收到取消信号......");
}
}, cst.Token);
Thread.Sleep(1000);
//1秒后结束
cst.Cancel();
Console.ReadKey();
// 情况二: 延迟取消
CancellationTokenSource cst2 = new CancellationTokenSource();
Task t2 = Task.Run(() => {
while (!cst2.IsCancellationRequested)
{
Console.WriteLine("情况二,没有接收到取消信号......");
}
}, cst2.Token);
//1秒后结束
cst2.CancelAfter(1000);
Console.ReadKey();
}
// 通过start方法
private void button1_Click(object sender, EventArgs e)
{
Task t = new Task(() =>
{
// 为界面控件赋值
this.textBox1.Text = "线程内赋值";
});
task.Start(TaskScheduler.FromCurrentSynchronizationContext());
}
// 通过延续方法
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
Thread.Sleep(1000);
}).ContinueWith(t => {
this.textBox1.Text = "线程内赋值";
}, TaskScheduler.FromCurrentSynchronizationContext());
}
static void test7()
{
Task t = Task.Run(() =>
{
throw new Exception("异常抛出.....");
});
try
{
t.Wait();
}
catch (AggregateException ex)
{
Console.Error.WriteLine(ex.Message);
foreach (var item in ex.InnerExceptions)
{
Console.WriteLine("内异常:"+item.Message);
}
//将异常往外抛出
// ex.Handle(p => false);
}
Console.ReadKey();
}
输出结果
One or more errors occurred. (异常抛出.....)
内异常:异常抛出.....
更多**好看的内容**和**好玩的案例**请关注**我的微信公众号: 程序猿知秋**