多线程(4)Task

  使用线程池使得创建线程已经很简单了,但是使用线程池不支持线程的取消,完成和失败通知等交互操作,为了解决这些问题,.net 4.0带来了TPL(Task Parallel Library)任务并行库,下面就来总结下Task的使用。

创建和运行任务

在.net 4.0下使用task创建一个线程非常简单,有两种方式,如下代码:

 1 namespace ConsoleApplication19
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //方法1
 8             var task1 = new Task(() =>
 9             {
10                 Console.WriteLine("Create and start task!");
11             });
12             task1.Start();
13
14             //方法2
15             Task.Factory.StartNew(() =>
16             {
17                 Console.WriteLine("Task factory start new task!");
18             });
19
20             Console.ReadKey();
21         }
22     }
23 }

输出结果:

需要注意的是:task也是基于线程池的,所以这两个任务的执行顺序是不固定的。

取消任务

创建一个新的任务之后,我们随时都可以取消它,取消方法如下代码:

 1 namespace ConsoleApplication20
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Console.WriteLine("Main thread starting...");
 8
 9             var cts = new CancellationTokenSource();
10             var task1 = Task.Factory.StartNew(() =>
11             {
12                 TaskAction(cts.Token);
13             });
14
15             Thread.Sleep(3000);
16             Console.WriteLine(string.Format("current task status::{0}", task1.Status));
17
18             //取消任务
19             cts.Cancel();
20             Console.WriteLine("start cancel task!");
21             for (int i = 0; i < 5; i++)
22             {
23                 Thread.Sleep(500);
24                 Console.WriteLine(string.Format("current task status::{0}", task1.Status));
25             }
26
27             Console.WriteLine("Main thread completed!");
28             Console.ReadKey();
29         }
30
31         public static void TaskAction(CancellationToken token)
32         {
33             Console.WriteLine("Sub thread starting...");
34
35             while (true)
36             {
37                 Thread.Sleep(1000);
38                 if (token.IsCancellationRequested)
39                 {
40                     Console.WriteLine("Sub thread be cancelled!");
41                     return;
42                 }
43                 Console.WriteLine("Sub thread is running!");
44             }
45         }
46
47     }
48 }

输出结果:

创建任务集合并输出结果

如下代码:

 1 namespace ConsoleApplication21
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //创建任务集合并输出结果
 8             var tasks = new List<Task<string>>();
 9
10             var task1 = Task.Factory.StartNew<string>(() =>
11             {
12                 Console.WriteLine("task1 running on thread id:"+ Thread.CurrentThread.ManagedThreadId);
13                 return "task1";
14             });
15             tasks.Add(task1);
16
17             var task2 = Task.Factory.StartNew<string>(() =>
18             {
19                 Console.WriteLine("task2 running on thread id:" + Thread.CurrentThread.ManagedThreadId);
20                 return "task2";
21             });
22             tasks.Add(task2);
23
24             var task3 = Task.Factory.StartNew<string>(() =>
25             {
26                 Console.WriteLine("task3 running on thread id:" + Thread.CurrentThread.ManagedThreadId);
27                 return "task3";
28             });
29             tasks.Add(task3);
30
31             //输出结果
32             foreach (var item in tasks)
33             {
34                 Console.WriteLine(item.Result);//调用Task的Result方法相当于调用了Task.WaitAll(tasks.ToArray());
35             }
36
37             Console.ReadKey();
38         }
39     }
40 }

输出结果:

这里要注意2点:

1,每个任务会开启一个新的线程,并且运行顺序不固定。

2,Task.Result相当于调用了Wait方法,等待异步任务完成。

多任务的串行化

如下代码:

 1 namespace ConsoleApplication22
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //多任务的串行化
 8             var task1 = Task.Factory.StartNew(() =>
 9             {
10                 Console.WriteLine("start task1...");
11                 Console.WriteLine("current thread id:"+ Thread.CurrentThread.ManagedThreadId);
12             });
13
14             var task2 = task1.ContinueWith((item) =>
15             {
16                 Console.WriteLine("start task2...");
17                 Console.WriteLine("current thread id:" + Thread.CurrentThread.ManagedThreadId);
18             });
19
20             var task3 = task2.ContinueWith((item)=>
21             {
22                 Console.WriteLine("start task3...");
23                 Console.WriteLine("current thread id:" + Thread.CurrentThread.ManagedThreadId);
24             });
25
26             Console.ReadKey();
27         }
28     }
29 }

输出结果:

注意,多任务串行化后,就相当于顺序执行了,而且有可能使用的是同一个线程,从上图的thread id就可以看出来。

多任务等待执行完成

如下代码:

 1 namespace ConsoleApplication23
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //多任务等待执行完成
 8             var tasks = new List<Task<string>>();
 9
10             var task1 = Task.Factory.StartNew<string>(() =>
11             {
12                 Console.WriteLine("task1");
13                 return "task1";
14             });
15             tasks.Add(task1);
16
17             var task2 = Task.Factory.StartNew<string>(() =>
18             {
19                 Console.WriteLine("task2");
20                 return "task2";
21             });
22             tasks.Add(task2);
23
24             var task3 = Task.Factory.StartNew<string>(() =>
25             {
26                 Console.WriteLine("task3");
27                 return "task3";
28             });
29             tasks.Add(task3);
30
31             //等待所有任务完成
32             Task.WaitAll(tasks.ToArray());
33
34             //等价于下面的调用
35             //foreach (var item in tasks)
36             //{
37             //    item.Result
38             //}
39
40             Console.ReadKey();
41         }
42     }
43 }

输出结果:

需要注意的是,如果是有返回值的task,可以使用Task.Result获取返回值的同时,也在等待Task执行完成,相当于调用了Task.Wait方法。

创建子任务

如下代码:

 1 namespace ConsoleApplication24
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //创建子任务
 8             var parentTask = Task.Factory.StartNew(() =>
 9             {
10                 Console.WriteLine("parent task!");
11                 var childTask = Task.Factory.StartNew(() =>
12                 {
13                     Console.WriteLine("child task!");
14                 }, TaskCreationOptions.AttachedToParent);
15             });
16
17             Console.ReadKey();
18         }
19     }
20 }

输出结果:

时间: 2024-10-03 04:49:01

多线程(4)Task的相关文章

【多线程】Task ,async ,await

一. WinForm 里经常会用到多线程, 多线程的好出就不多说了,来说说多线程比较麻烦的地方 1. UI 线程与其他线程的同步,主要是 Form 和 Control 在跨线程时的使用,这里是值得注意的,因为少有不甚就会出错. 二. 常用的跨线程方法 1.  Invoke : 同步调用, 因为是同步操作,所以如果操作 UI 的方法很耗时,就不推荐了,得用 BeginInvoke. 代码: private void button1_Click(object sender, EventArgs e)

.Net 多线程 (1) Task

多线程是一种有效提高程序工作效率的方法.当然为了效率需要使用更多的cpu,内存等资源. 并发是两个队列交替使用一台咖啡机,并行是两个队列同时使用两台咖啡机,如果串行,一个队列使用一台咖啡机,那么哪怕前面那个人便秘了去厕所呆半天,后面的人也只能死等着他回来才能去接咖啡,这效率无疑是最低的. 并发和并行都可以是很多个线程,就看这些线程能不能同时被(多个)cpu执行,如果可以就说明是并行,而并发是多个线程被(一个)cpu 轮流切换着执行. 运行一个线程 1 class Program 2 { 3 st

【多线程】Task

介绍 Task是.NET推出数据任务处理的工作类.位于System.Threading.Tasks命名空间下,通过命名空间也可以看出是个多线程类. 创建Task: Task有很多构造函数,无参有参都有,想了解更多可以去官网查看.这里只介绍经常用的形式. 第一种:以类的实例化形式进行创建Task.通过实例化一个Task对象,然后Start,这种方式中规中矩. Task Task1 = new Task(() => Console.WriteLine("Task")); Task1.

SpringBoot多线程执行task任务

一.问题描述 Task定时任务默认都是使用单线程执行的,如果定时任务有很多的话,那么可能会导致很多任务无法按时准确执行,示例如下: import java.text.SimpleDateFormat; import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; import or

C#多线程编程のTask(任务)

Task是.NET4.5加入的,跟线程池ThreadPool的功能类似,用Task开启新任务时,会从线程池中调用线程,而Thread每次实例化都会创建一个新的线程. 长耗时操作是不是常用 await Task.Run( )? 看下面代码: namespace WpfApplication6 { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window

【多线程】 Task

一. 常用方法: 1. ContinueWith : 当前 Task 完成后, 执行传入的 Task 2. Delay : 创建一个等待的 Task,只有在调用 Wait 方法时才会阻塞 (注意:与 Thread.Sleep 不同) 3. Run : 创建一个 Task 并执行 4. Start : 执行 Task 5. Wait : 在一定时间内阻塞线程, 直到 Task 完成或超过等待时间时取消阻塞 6. WaitAll : 阻塞线程直到所有的 Task 完成或超过等待时间 7. WaitA

初步谈谈 C# 多线程、异步编程与并发服务器

多线程与异步编程可以达到避免调用线程异步阻塞作用,但是两者还是有点不同. 多线程与异步编程的异同: 1.线程是cpu 调度资源和分配的基本单位,本质上是进程中的一段并发执行的代码. 2.线程编程的思维符合正常人的思维习惯,线程中的处理程序依然是顺序执行,所以编程起来比较方便,但是缺点也是明显的,多线程的使用会造成多线程之间的上下文切换带来系统花销,并且共享变量之间也是会造成死锁的问题. 3.因为异步操作无须额外的线程负担,并且使用回调的方式进行处理,在设计良好的情况下,处理函数可以不必使用共享变

C# Task中的Func, Action, Async与Await的使用

在说Asnc和Await之前,先说明一下Func和Action委托, Task任务的基础的用法 1. Func Func是一种委托,这是在3.5里面新增的,2.0里面我们使用委托是用Delegate,Func位于System.Core命名空间下,使用委托可以提升效率,例如在反射中使用就可以弥补反射所损失的性能. Action<T>和Func<T,TResult>的功能是一样的,只是Action<T>没有返类型, Func<T,T,Result>:有参数,有返

Threads(异步和多线程)

原文:Threads(异步和多线程) Task是.NET Framework3.0出现的,线程是基于线程池的,然后提供丰富的api,Thread方法很多很强大,但是太过强大,没有限制. DoSomethingLong方法如下: /// <summary> /// 一个比较耗时耗资源的私有方法 /// </summary> /// <param name="name"></param> private void DoSomethingLon