赞
踩
task简单地看就是任务,那和thread有什么区别呢?Task的背后的实现也是使用了线程池线程,但它的性能优于ThreadPoll,因为它使用的不是线程池的全局队列,而是使用的本地队列,使线程之间的资源竞争减少。同时Task提供了丰富的API来管理线程、控制。但是相对前面的两种耗内存,Task依赖于CPU对于多核的CPU性能远超前两者,单核的CPU三者的性能没什么差别。
1.使用factory创建会直接执行,使用new创建不会执行,必须等到start启动之后才执行。
-
- public void test()
- {
- var testTask = new Task(() =>
- {
- Console.WriteLine("task start");
- });
- testTask.Start();
- var factoryTeak = Task.Factory.StartNew(() =>
- {
- Console.WriteLine("factory task start");
- });
- }
-
-
2.我们来看看task的生命周期
-
- var testTask = new Task(() =>
- {
- Console.WriteLine("task start");
- System.Threading.Thread.Sleep(2000);
- });
- Console.WriteLine(testTask.Status);
- testTask.Start();
- Console.WriteLine(testTask.Status);
- Console.WriteLine(testTask.Status);
- testTask.Wait();
- Console.WriteLine(testTask.Status);
- Console.WriteLine(testTask.Status);
-
-
输出结果:
Created
task start
Running
Running
RanToCompletion
RanToCompletion
可以看出task确实是异步执行,并且wait很好地控制了task。
3.下面演示几个控制task的方法
- var testTask = new Task(() =>
- {
- Console.WriteLine("task start");
- System.Threading.Thread.Sleep(2000);
- });
- testTask.Start();
- testTask.Wait();
-
- var testTask = new Task(() =>
- {
- Console.WriteLine("task start");
- System.Threading.Thread.Sleep(2000);
- });
- testTask.Start();
- var factoryTeak = Task.Factory.StartNew(() =>
- {
- Console.WriteLine("factory task start");
- });
- Task.WaitAll(testTask, factoryTeak);
- Console.WriteLine("end");
-
-
- var testTask = new Task(() =>
- {
- Console.WriteLine("task start");
- System.Threading.Thread.Sleep(2000);
- });
- testTask.Start();
- var factoryTeak = Task.Factory.StartNew(() =>
- {
- Console.WriteLine("factory task start");
- });
- Task.WaitAny(testTask, factoryTeak);
- Console.WriteLine("end");
通过wait()对单个task进行等待,Task.waitall()对多个task进行等待,waitany()执行任意一个task就往下继续执行。
4.task的回调执行
- var testTask = new Task(() =>
- {
- Console.WriteLine("task start");
- System.Threading.Thread.Sleep(2000);
- });
- testTask.Start();
- var resultTest = testTask.ContinueWith<string>((Task) => {
- Console.WriteLine("testTask end");
- return "end";
- });
- Console.WriteLine(resultTest.Result);
5.task的取消
首先创建一个取消task的令牌的实例,在不启动task直接取消:
- var tokenSource = new CancellationTokenSource();//创建取消task实例
- var testTask = new Task(() =>
- {
- for (int i = 0; i < 6; i++) {
- System.Threading.Thread.Sleep(1000);
- }
- },tokenSource.Token);
- Console.WriteLine(testTask.Status);
- tokenSource.Token.Register(()=> {
- Console.WriteLine("task is to cancel");
- });
- tokenSource.Cancel();
- Console.WriteLine(testTask.Status);
输出结果:
Created
task is to cancel
Canceled
如果task启动了真的取消了task?
- var tokenSource = new CancellationTokenSource();//创建取消task实例
- var testTask = new Task(() =>
- {
- for (int i = 0; i <6; i++) {
- System.Threading.Thread.Sleep(1000);
- }
- },tokenSource.Token);
- Console.WriteLine(testTask.Status);
- testTask.Start();
- Console.WriteLine(testTask.Status);
- tokenSource.Token.Register(()=> {
- Console.WriteLine("task is to cancel");
- });
- tokenSource.Cancel();
- Console.WriteLine(testTask.Status);
- for (int i = 0; i < 10; i++)
- {
- System.Threading.Thread.Sleep(1000);
- Console.WriteLine(testTask.Status);
- }
输出结果:
Created
WaitingToRun
task is to cancel
Running
Running
Running
Running
Running
Running
RanToCompletion
RanToCompletion
RanToCompletion
RanToCompletion
RanToCompletion
可以看出其实并没有取消task,此时task还在继续跑。
6.task的嵌套
- var parentTask = new Task(()=> {
- var childTask = new Task(() =>{
- System.Threading.Thread.Sleep(2000);
- Console.WriteLine("childTask to start");
- });
- childTask.Start();
- Console.WriteLine("parentTask to start");
- });
- parentTask.Start();
- parentTask.Wait();
- Console.WriteLine("end");
此时为普通关联,父task和子task没影响
- var parentTask = new Task(()=> {
- var childTask = new Task(() =>{
- System.Threading.Thread.Sleep(2000);
- Console.WriteLine("childTask to start");
- }, TaskCreationOptions.AttachedToParent);
- childTask.Start();
- Console.WriteLine("parentTask to start");
- } );
- parentTask.Start();
- parentTask.Wait();
- Console.WriteLine("end");
此时为父task和子task关联,wait会一直等待父子task执行完。
6.task死锁的问题
我们可以设置最大等待时间,如果超过了等待时间,就不再等待,下面我们来修改代码,设置最大等待时间为5秒(项目中可以根据实际情况设置),如果超过5秒就输出哪个任务出错了
7.对Spinlock的使用
举例来说Parallel.for和Parallel.foreach是线程不安全的,有可能达不到你的预期,此时就需要加锁来解决此问题,我们可以加lock和spinlock(自旋锁)来解决
- SpinLock slock = new SpinLock(false);
- var testLock= new object();
- long sum1 = 0;
- long sum2 = 0;
- long sum3 = 0;
- Parallel.For(0, 100000, i =>
- {
- sum1 += i;
- });
-
- Parallel.For(0, 100000, i =>
- {
- bool lockTaken = false;
- try
- {
- slock.Enter(ref lockTaken);
- sum2 += i;
- }
- finally
- {
- if (lockTaken)
- slock.Exit(false);
- }
- });
- Parallel.For(0, 100000, i =>
- {
- lock(testLock)
- {
- sum3 += i;
- };
- });
- Console.WriteLine("Num1的值为:{0}", sum1);
- Console.WriteLine("Num2的值为:{0}", sum2);
- Console.WriteLine("Num3的值为:{0}", sum3);
输出结果:
Num1的值为:1660913202
Num2的值为:4999950000
Num3的值为:4999950000
Num1的值为:2754493646
Num2的值为:4999950000
Num3的值为:4999950000
Num1的值为:4999950000
Num2的值为:4999950000
Num3的值为:4999950000
最后看看threadpoll和task的结构图:
task:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。