设为首页 加入收藏

TOP

细说.NET中的多线程:使用Task(一)
2015-12-01 14:11:45 来源: 作者: 【 】 浏览:15
Tags:细说 .NET 线程 使用 Task

创建并且初始化Task


使用lambda表达式创建Task


Task.Factory.StartNew(() => Console.WriteLine("Hello from a task!"));


var task = new Task(() => Console.Write("Hello"));


task.Start();


用默认参数的委托创建Task


?


using System;


using System.Threading.Tasks;


namespace MultiThread


{


? ? class ThreadTest


? ? {


? ? ? ? static void Main()


? ? ? ? {


? ? ? ? ? ? var task = Task.Factory.StartNew(state => Greet("Hello"), "Greeting");


? ? ? ? ? ? Console.WriteLine(task.AsyncState);? // Greeting


? ? ? ? ? ? task.Wait();


? ? ? ? }


? ? ? ? static void Greet(string message) { Console.Write(message); }


? ? }


}


这种方式的一个优点是,task.AsyncState作为一个内置的属性,可以在不同线程中获取参数的状态。


System.Threading.Tasks.TaskCreateOptions


创建Task的时候,我们可以指定创建Task的一些相关选项。在.Net 4.0中,有如下选项:


LongRunning


用来表示这个Task是长期运行的,这个参数更适合block线程。LongRunning线程一般回收的周期会比较长,因此CLR可能不会把它放到线程池中进行管理。


PreferFairness


表示让Task尽量以公平的方式运行,避免出现某些线程运行过快或者过慢的情况。


AttachedToParent


表示创建的Task是当前线程所在Task的子任务。这一个用途也很常见。


下面的代码是创建子任务的示例:


using System;


using System.Threading;


using System.Threading.Tasks;


namespace MultiThread


{


? ? class ThreadTest


? ? {


? ? ? ? public static void Main(string[] args)


? ? ? ? {


? ? ? ? ? ? Task parent = Task.Factory.StartNew(() =>


? ? ? ? ? ? {


? ? ? ? ? ? ? ? Console.WriteLine("I am a parent");


? ? ? ? ? ? ? ? Task.Factory.StartNew(() =>? ? ? ? // Detached task


? ? ? ? ? ? ? ? {


? ? ? ? ? ? ? ? ? ? Console.WriteLine("I am detached");


? ? ? ? ? ? ? ? });


? ? ? ? ? ? ? ? Task.Factory.StartNew(() =>? ? ? ? // Child task


? ? ? ? ? ? ? ? {


? ? ? ? ? ? ? ? ? ? Console.WriteLine("I am a child");


? ? ? ? ? ? ? ? }, TaskCreationOptions.AttachedToParent);


? ? ? ? ? ? });


? ? ? ? ? ? parent.Wait();


? ? ? ? ? ? Console.ReadLine();


? ? ? ? }


? ? }


}


如果你等待你一个任务结束,你必须同时等待任务里面的子任务结束。这一点很重要,尤其是你在使用Continue的时候。(后面会介绍)


等待Task


在ThreadPool内置的方法中无法实现的等待,在Task中可以很简单的实现了:


using System;


using System.Threading;


using System.Threading.Tasks;


namespace MultiThread


{


? ? class ThreadTest


? ? {


? ? ? ? static void Main()


? ? ? ? {


? ? ? ? ? ? var t1 = Task.Run(() => Go(null));


? ? ? ? ? ? var t2 = Task.Run(() => Go(123));


? ? ? ? ? ? Task.WaitAll(t1, t2);//等待所有Task结束


? ? ? ? ? ? //Task.WaitAny(t1, t2);//等待任意Task结束


? ? ? ? }


? ? ? ? static void Go(object data)? // data will be null with the first call.


? ? ? ? {


? ? ? ? ? ? Thread.Sleep(5000);


? ? ? ? ? ? Console.WriteLine("Hello from the thread pool! " + data);


? ? ? ? }


? ? }


}


注意:


当你调用一个Wait方法时,当前的线程会被阻塞,直到Task返回。但是如果Task还没有被执行,这个时候系统可能会用当前的线程来执行调用Task,而不是新建一个,这样就不需要重新创建一个线程,并且阻塞当前线程。这种做法节省了创建新线程的开销,也避免了一些线程的切换。但是也有缺点,当前线程如果和被调用的Task同时想要获得一个lock,就会导致死锁。


Task异常处理


当等待一个Task完成的时候(调用Wait或者或者访问Result属性的时候),Task任务中没有处理的异常会被封装成AggregateException重新抛出,InnerExceptions属性封装了各个Task没有处理的异常。


using System;


using System.Threading.Tasks;


namespace MultiThreadTest


{


? ? class Program


? ? {


? ? ? ? static void Main(string[] args)


? ? ? ? {


? ? ? ? ? ? int x = 0;


? ? ? ? ? ? Task calc = Task.Factory.StartNew(() => 7 / x);


? ? ? ? ? ? try


? ? ? ? ? ? {


? ? ? ? ? ? ? ? Console.WriteLine(calc.Result);


? ? ? ? ? ? }


? ? ? ? ? ? catch (AggregateException aex)


? ? ? ? ? ? {


? ? ? ? ? ? ? ? Console.Write(aex.InnerException.Message);? // Attempted to divide by 0


? ? ? ? ? ? }


? ? ? ? }


? ? }


}


对于有父子关系的Task,子任务未处理的异常会逐层传递到父Task,并且最后包装在AggregateException中。


using System;


using System.Threading.Tasks;


namespace MultiThreadTest


{


? ? class Program


? ? {


? ? ? ? static void Main(string[] args)


? ? ? ? {


? ? ? ? ? ? TaskCreationOptions atp = TaskCreationOptions.AttachedToParent;


? ? ? ? ? ? var parent = Task.Factory.StartNew(() =>


? ? ? ? ? ? {


? ? ? ? ? ? ? ? Task.Factory.StartNew(() =>? // Child


? ? ? ? ? ? ? ? {


? ? ? ? ? ? ? ? ? ? Task.Factory.StartNew(() => { throw null; },

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇土耳其屏蔽Reddit 下一篇细说.NET中的多线程:线程池

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: