Task构造
//原文: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构造的更多相关文章
- Codeforces 959D. Mahmoud and Ehab and another array construction task(构造, 简单数论)
Codeforces 959D. Mahmoud and Ehab and another array construction task 题意 构造一个任意两个数都互质的序列,使其字典序大等于a序列 ...
- Codeforces 461D. Appleman and Complicated Task 构造,计数
原文链接https://www.cnblogs.com/zhouzhendong/p/CF461D.html 题解 首先我们可以发现如果确定了第一行,那么方案就唯一了. 然后,我们来看看一个点的值确定 ...
- cf1088C Ehab and a 2-operation task (构造)
题意:给一个数列,你可以进行至多n+1次操作,每次给一个前缀对某数取模或者加某数,使得最后数列严格单增 考虑到因为是前缀和而且还不能加负数,光靠加是不能让前面的小于后面的 所以要让他先在模某数意义下单 ...
- Codeforces - 1114B - Yet Another Array Partitioning Task - 构造 - 排序
https://codeforces.com/contest/1114/problem/B 一开始叫我做,我是不会做的,我没发现这个性质. 其实应该很好想才对,至少要选m个元素,其中m个作为最大值,从 ...
- 【kAriOJ】离散数学 构造群码 极大似然法解码
A. 编程题1 构造群码 时间限制 1000 ms 内存限制 65536 KB 题目描述 针对给定H,计算群码编码函数eH,并计算给定字的码字. 输入格式 第一行输入两个整数m,n:(m < n ...
- 【Hadoop代码笔记】Hadoop作业提交之TaskTracker获取Task
一.概要描述 在上上一篇博文和上一篇博文中分别描述了jobTracker和其服务(功能)模块初始化完成后,接收JobClient提交的作业,并进行初始化.本文着重描述,JobTracker如何选择作业 ...
- Hadoop作业提交之TaskTracker获取Task
[Hadoop代码笔记]Hadoop作业提交之TaskTracker获取Task 一.概要描述 在上上一篇博文和上一篇博文中分别描述了jobTracker和其服务(功能)模块初始化完成后,接收JobC ...
- 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 ...
- C#知识点记录
用于记录C#知识要点. 参考:CLR via C#.C#并发编程.MSDN.百度 记录方式:读每本书,先看一遍,然后第二遍的时候,写笔记. CLR:公共语言运行时(Common Language Ru ...
随机推荐
- uva-657-搜索
注意是四个方向(上下左右),不是八个方向,当成了八个方向做,一直wa AC时间:0ms #include<stdio.h> #include<iostream> #includ ...
- leetcode976
public class Solution { public int LargestPerimeter(int[] A) { var list = A.OrderByDescending(x => ...
- 转发 DDoS攻防战 (一) : 概述
岁寒 然后知松柏之后凋也 岁寒 然后知松柏之后凋也 ——论语·子罕 (此图摘自<Web脚本攻击与防御技术核心剖析>一书,作者:郝永清先生) DDoS,即 Distributed ...
- Declaration terminated incorrectly 讨厌 这样就不可以了
#include "vcl.fctreeview.hpp"#include "RM_Class.hpp"#include "RM_Common.hpp ...
- 使用Ping来做等待的时间计算
利用ping两次发送消息之间的间隔时间.ping在发送多个消息时,在得到上一次消息的回应后,它会再等待1秒的时间才发送下一次消息,而这个回应时间因机型.系统和网络配置而不同,其中IP地址尤其关键,只有 ...
- PHP图像 因其本身有错无法显示
昨天终于将客户的一个网站迁移至虚拟主机上,满怀希望的敲入网址.唰的一声,网站很轻松的被打开了. 心里那个高兴啊~~~ 咦,怎么产品图片都没有显示出来.一块块都是空白.敲入img src对应的地址,看看 ...
- Simple2D-23(重构)反走样几何图形
以前 Simple2D 使用 Canvas2D 对象来绘制几何图形,而且渲染出来的几何图形存在明显的锯齿.如果想要抗锯齿的几何图形,则需要开启 OpenGL 的 MSAA,这需要很大的开销. 如果不使 ...
- NDK开发中的一个HTTP下载实例附带下载进度
有一个控制下载的管理类吧,调用http下载类进行各种下载,同时在下载过程中可以显示其下载的进度,而且在每个下载结束之后以类似回调的方式告诉管理类,以继续进行后续的操作. 直接代码: .h文件 #pra ...
- javascript事件之鼠标滚轮(mousewheel)和DOMMouseScroll事件
javascript事件之鼠标滚轮(mousewheel)和DOMMouseScroll事件 发布时间:2015-02-07 编辑:www.jquerycn.cn 本文学习下,javascript ...
- mysql启动报错 The server quit without updating PID file
[root@uz6542 data]# /etc/init.d/mysqld startStarting MySQL... ERROR! The server quit without updatin ...