//原文:http://www.tuicool.com/articles/IveiQbQ
创建并且初始化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 .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());
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();
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 = ;
Task<int> calc = Task.Factory.StartNew(() => / 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; }, atp); // Grandchild
}, atp);
});
// The following call throws a NullReferenceException (wrapped
// in nested AggregateExceptions):
parent.Wait();
}
}
}
取消Task
如果想要支持取消任务,那么在创建Task的时候,需要传入一个CancellationTokenSouce
示例代码:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MultiThreadTest
{
class Program
{
static void Main(string[] args)
{
var cancelSource = new CancellationTokenSource();
CancellationToken token = cancelSource.Token;
Task task = Task.Factory.StartNew(() =>
{
// Do some stuff...
token.ThrowIfCancellationRequested(); // Check for cancellation request
// Do some stuff...
}, token);
cancelSource.Cancel();
try
{
task.Wait();
}
catch (AggregateException ex)
{
if (ex.InnerException is OperationCanceledException)
Console.Write("Task canceled!");
}
Console.ReadLine();
}
}
}
任务的连续执行
Continuations
任务调度也是常见的需求,Task支持一个任务结束之后执行另一个任务。
Task task1 = Task.Factory.StartNew(() => Console.Write("antecedant.."));
Task task2 = task1.ContinueWith(task =>Console.Write("..continuation"));
Continuations 和Task<TResult>
Task也有带返回值的重载,示例代码如下:
Task.Factory.StartNew<int>(() => )
.ContinueWith(ant => ant.Result * )
.ContinueWith(ant => Math.Sqrt(ant.Result))
.ContinueWith(ant => Console.WriteLine(ant.Result)); // output 4
子任务
前面提到了,当你等待一个任务的时候,同时需要等待它的子任务完成。
下面代码演示了带子任务的Task:
using System;
using System.Threading.Tasks;
using System.Threading;
namespace MultiThreadTest
{
class Program
{
public static void Main(string[] args)
{
Task<int[]> parentTask = Task.Factory.StartNew(() =>
{
int[] results = new int[];
Task t1 = new Task(() => { Thread.Sleep(); results[] = ; }, TaskCreationOptions.AttachedToParent);
Task t2 = new Task(() => { Thread.Sleep(); results[] = ; }, TaskCreationOptions.AttachedToParent);
Task t3 = new Task(() => { Thread.Sleep(); results[] = ; }, TaskCreationOptions.AttachedToParent);
t1.Start();
t2.Start();
t3.Start();
return results;
});
Task finalTask = parentTask.ContinueWith(parent =>
{
foreach (int result in parent.Result)
{
Console.WriteLine(result);
}
});
finalTask.Wait();
Console.ReadLine();
}
}
}
这段代码的输出结果是: ,,
FinalTask会等待所有子Task结束后再执行。
TaskFactory
关于TaskFactory,上面的例子中我们使用了System.Threading.Tasks .Task.Factory属性来快速的创建Task。当然你也可以自己创建TaskFactory,你可以指定自己的TaskCreationOptions,TaskContinuationOptions来使得通过你的Factory创建的Task默认行为不同。
.Net中有一些默认的创建Task的方式,由于TaskFactory创建Task的默认行为不同可能会导致一些不容易发现的问题。
如在.NET .5中,Task加入了一个Run的静态方法:
Task.Run(someAction);
如果你用这个方法代替上面例子中的Task.Factory.StartNew,就无法得到正确的结果。原因是Task.Run创建Task的行为默认是默认是拒绝添加子任务的。上面的代码等价于:
Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
你也可以创建具有自己默认行为的TaskFactory。
无论ThreadPool也好,或者Task,微软都是在想进办法来实现线程的重用,来节省不停的创建销毁线程带来的开销。线程池内部的实现可能在不同版本中有不同的机制。如果可能的话,使用线程池来管理线程仍然是建议的选择。
作者:独上高楼
出处: http://www.cnblogs.com/myprogram/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

Task构造的更多相关文章

  1. Codeforces 959D. Mahmoud and Ehab and another array construction task(构造, 简单数论)

    Codeforces 959D. Mahmoud and Ehab and another array construction task 题意 构造一个任意两个数都互质的序列,使其字典序大等于a序列 ...

  2. Codeforces 461D. Appleman and Complicated Task 构造,计数

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF461D.html 题解 首先我们可以发现如果确定了第一行,那么方案就唯一了. 然后,我们来看看一个点的值确定 ...

  3. cf1088C Ehab and a 2-operation task (构造)

    题意:给一个数列,你可以进行至多n+1次操作,每次给一个前缀对某数取模或者加某数,使得最后数列严格单增 考虑到因为是前缀和而且还不能加负数,光靠加是不能让前面的小于后面的 所以要让他先在模某数意义下单 ...

  4. Codeforces - 1114B - Yet Another Array Partitioning Task - 构造 - 排序

    https://codeforces.com/contest/1114/problem/B 一开始叫我做,我是不会做的,我没发现这个性质. 其实应该很好想才对,至少要选m个元素,其中m个作为最大值,从 ...

  5. 【kAriOJ】离散数学 构造群码 极大似然法解码

    A. 编程题1 构造群码 时间限制 1000 ms 内存限制 65536 KB 题目描述 针对给定H,计算群码编码函数eH,并计算给定字的码字. 输入格式 第一行输入两个整数m,n:(m < n ...

  6. 【Hadoop代码笔记】Hadoop作业提交之TaskTracker获取Task

    一.概要描述 在上上一篇博文和上一篇博文中分别描述了jobTracker和其服务(功能)模块初始化完成后,接收JobClient提交的作业,并进行初始化.本文着重描述,JobTracker如何选择作业 ...

  7. Hadoop作业提交之TaskTracker获取Task

    [Hadoop代码笔记]Hadoop作业提交之TaskTracker获取Task 一.概要描述 在上上一篇博文和上一篇博文中分别描述了jobTracker和其服务(功能)模块初始化完成后,接收JobC ...

  8. C#与C++的发展历程第三 - C#5.0异步编程巅峰

    系列文章目录 1. C#与C++的发展历程第一 - 由C#3.0起 2. C#与C++的发展历程第二 - C#4.0再接再厉 3. C#与C++的发展历程第三 - C#5.0异步编程的巅峰 C#5.0 ...

  9. C#知识点记录

    用于记录C#知识要点. 参考:CLR via C#.C#并发编程.MSDN.百度 记录方式:读每本书,先看一遍,然后第二遍的时候,写笔记. CLR:公共语言运行时(Common Language Ru ...

随机推荐

  1. 一,Android Studio笔记

    转自:https://developer.android.com/studio/intro/index.html 一.界面 Android Studio 主窗口由图 3 标注的几个逻辑区域组成. 工具 ...

  2. 随着firefox的迭代更新:FireBug不能用了?使用火狐Try Xpath插件替代Firebug和Firepath

    本篇文章讲解如何在火狐中安装和使用Try Xpath(插件替代Firebug和Firepath). 在火狐中安装Try Xpath 1. 打开火狐浏览器 FireFox57以上的版本 2. 在火狐菜单 ...

  3. django的小操作,查询效率up, 引用art-template模板+djangorestframework

    Part1: 提高查询效率newses = News.objects.select_related('category', 'author').get(id=1) # category和author字 ...

  4. tensorflow data's save and load

    note: if you'll load data,the data shape should be similar with saved data's shape.    -- 中式英语,天下无敌 ...

  5. etcd查看key-value

    get/set key-value etcdctl get/set /key-path etcdctl watch --recursive /test/sm/default/apps 查看所有key- ...

  6. 33. Linux安装配置JDK-7

    安装说明 系统环境:centos-6.3安装方式:rpm安装 软件:jdk-7-linux-x64.rpm下载地址:http://www.oracle.com/technetwork/java/jav ...

  7. ASP.net显示当前系统在线人数

    void Application_Start(object sender, EventArgs e) { // 在应用程序启动时运行的代码 Application.Lock(); if (Applic ...

  8. json和java bean的相互转换(使用fastjson)

    <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifac ...

  9. cb6xe7代码提示风格变化

  10. 让apache支持htaccess文件

    第一:检测 apache是否开启mod_rewrite 通过php提供的phpinfo()函数查看环境配置,在"apache2handler -> Loaded Modules&quo ...