.NET 4并行编程入门之Task的休眠

开发 后端
本文将介绍的是Task的休眠,这也是本.NET 4并行编程系列文章的第四篇。通过休眠,可以起到提高利用效率的作用。

查看本系列其他文章,请参看

[[11751]]

本篇的议题如下:

1.Task的休眠。

1. Task的休眠

有时候,我们常常希望一个Task在等待一段时间之后再运行,也就有点类似之前多线程编程中的Sleep。我们可以设置一个Task休眠多长时间,当这个时间过了,Task就自动的唤醒接着运行。

下面就讲讲休眠的方法:

a.使用CancellationToken的Wait Handle:

a)  在.NET 4并行编程中,让一个Task休眠的最好的方式就是使用CancellationToken的等待操作(Wait Handle)。而且操作起来也很简单:首先创建一个CancellationTokenSource的实例,然后通过这个实例的Token属性得到一个CancellationToken的实例,然后在用CancellationToken的WaitHandle属性,然后调用这个这个属性的WaitOne()方法。其实在之前讲述”Task的取消”一文中就已经使用过。

b)  WaitOne()方法有很多的重载方法来提供更多的功能,例如可以传入一个int的整数,表明要休眠多长的时间,单位是微秒,也可以传入一个TimeSpan的值。如果调用了CancellationToken的Cancel()方法,那么休眠就立刻结束。就是因为这个原因,我们之前的文章讲过,WaitOne()可以作为检测Task是否被取消的一个方案

下面来看一段示例代码:

代码 
 

  1. static void Main(string[] args)  
  2. {  
  3.     // create the cancellation token source  
  4.     CancellationTokenSource tokenSource = new CancellationTokenSource();  
  5.  
  6.     // create the cancellation token  
  7.     CancellationToken token = tokenSource.Token;  
  8.  
  9.     // create the first task, which we will let run fully  
  10.     Task task1 = new Task(() =>  
  11.     {  
  12.  for (int i = 0; i < Int32.MaxValue; i++)  
  13.  {  
  14.      // put the task to sleep for 10 seconds  
  15.      bool cancelled = token.WaitHandle.WaitOne(10000);  
  16.      // print out a message  
  17.      Console.WriteLine("Task 1 - Int value {0}. Cancelled? {1}",  
  18.      i, cancelled);  
  19.      // check to see if we have been cancelled  
  20.      if (cancelled)  
  21.      {  
  22.   throw new OperationCanceledException(token);  
  23.      }  
  24.  }  
  25.     }, token);  
  26.     // start task  
  27.     task1.Start();  
  28.  
  29.     // wait for input before exiting  
  30.     Console.WriteLine("Press enter to cancel token.");  
  31.     Console.ReadLine();  
  32.  
  33.     // cancel the token  
  34.     tokenSource.Cancel();  
  35.  
  36.     // wait for input before exiting  
  37.     Console.WriteLine("Main method complete. Press enter to finish.");  
  38.     Console.ReadLine();  

 

在上面的代码中,task在休眠了10秒钟之后就打印出一条信息。在例子中,在我们敲一下键盘之后,CancellationToken就会被Cancel,此时休眠就停止了,task重新唤醒,只不过是这个task将会被cancel掉。

有一点要注意:WaitOne()方法只有在设定的时间间隔到了,或者Cancel方法被调用,此时task才会被唤醒。如果如果cancel()方法被调用而导致task被唤醒,那么CancellationToken.WaitHandle.WaitOne()方法就会返回true,如果是因为设定的时间到了而导致task唤醒,那么CancellationToken.WaitHandle.WaitOne()方法返回false。

b.task休眠的第二种方法:使用传统的Sleep。

我们现在已经知道了:其实TPL(并行编程)的底层还是基于.NET的线程机制的。所以还是可以用传统的线程技术来使得一个task休眠:调用静态方法—Thread.Sleep(),并且可以传入一个int类型的参数,表示要休眠多长时间。

代码 

  1. static void Main(string[] args)  
  2.  {  
  3.      // create the cancellation token source  
  4.      CancellationTokenSource tokenSource = new CancellationTokenSource();  
  5.  
  6.      // create the cancellation token  
  7.      CancellationToken token = tokenSource.Token;  
  8.  
  9.      // create the first task, which we will let run fully  
  10.      Task task1 = new Task(() =>  
  11.      {  
  12.   for (int i = 0; i < Int32.MaxValue; i++)  
  13.   {  
  14.       // put the task to sleep for 10 seconds  
  15.       Thread.Sleep(10000);  
  16.  
  17.       // print out a message  
  18.       Console.WriteLine("Task 1 - Int value {0}", i);  
  19.       // check for task cancellation  
  20.       token.ThrowIfCancellationRequested();  
  21.   }  
  22.      }, token);  
  23.      // start task  
  24.      task1.Start();  
  25.  
  26.      // wait for input before exiting  
  27.      Console.WriteLine("Press enter to cancel token.");  
  28.      Console.ReadLine();  
  29.  
  30.      // cancel the token  
  31.      tokenSource.Cancel();  
  32.  
  33.      // wait for input before exiting  
  34.      Console.WriteLine("Main method complete. Press enter to finish.");  
  35.      Console.ReadLine();  
  36.  } 

这种方法和之前第一种方法最大的区别就是:使用Thread.Sleep()之后,然后再调用token的cancel方法,task不会立即就被cancel,这主要是因为Thread.Sleep()将会一直阻塞线程,直到达到了设定的时间,这之后,再去check task时候被cancel了。举个例子,假设再task方法体内调用Thread.Sleep(100000)方法来休眠task,然后再后面的代码中调用token.Cancel()方法,此时处于并行编程内部机制不会去检测task是否已经发出了cancel请求,而是一直休眠,直到时间超过了100000微秒。如果采用的是之前的第一种休眠方法,那么不管WaitOne()中设置了多长的时间,只要token.Cancel()被调用,那么task就像内部的Scheduler发出了cancel的请求,而且task会被cancel。

c.第三种休眠方法:自旋等待.

这种方法也是值得推荐的。之前的两种方法,当他们使得task休眠的时候,这些task已经从Scheduler的管理中退出来了,不被再内部的Scheduler管理(Scheduler,这里只是简单的提下,因为后面的文章会详细讲述,这里只要知道Scheduler是负责管理线程的),因为休眠的task已经不被Scheduler管理了,所以Scheduler必须做一些工作去决定下一步是哪个线程要运行,并且启动它。为了避免Scheduler做那些工作,我们可以采用自旋等待:此时这个休眠的task所对应的线程不会从Scheduler中退出,这个task会把自己和CPU的轮转关联起来,我们还是用代码示例讲解吧。

代码 

  1. static void Main(string[] args)  
  2.  {  
  3.      // create the cancellation token source  
  4.      CancellationTokenSource tokenSource = new CancellationTokenSource();  
  5.  
  6.      // create the cancellation token  
  7.      CancellationToken token = tokenSource.Token;  
  8.  
  9.      // create the first task, which we will let run fully  
  10.      Task task1 = new Task(() =>  
  11.      {  
  12.   for (int i = 0; i < Int32.MaxValue; i++)  
  13.   {  
  14.       // put the task to sleep for 10 seconds  
  15.       Thread.SpinWait(10000);  
  16.       // print out a message  
  17.       Console.WriteLine("Task 1 - Int value {0}", i);  
  18.       // check for task cancellation  
  19.       token.ThrowIfCancellationRequested();  
  20.   }  
  21.      }, token);  
  22.  
  23.      // start task  
  24.      task1.Start();  
  25.  
  26.      // wait for input before exiting  
  27.      Console.WriteLine("Press enter to cancel token.");  
  28.  
  29.      Console.ReadLine();  
  30.      // cancel the token  
  31.      tokenSource.Cancel();  
  32.  
  33.      // wait for input before exiting  
  34.      Console.WriteLine("Main method complete. Press enter to finish.");  
  35.      Console.ReadLine();  
  36.  } 

代码中我们在Thread.SpinWait()方法中传入一个整数,这个整数就表示CPU时间片轮转的次数,至于要等待多长的时间,这个就和计算机有关了,不同的计算机,CPU的轮转时间不一样。自旋等待的方法常常于获得同步锁,后续会讲解。使用自旋等待会一直占用CPU,而且也会消耗CPU的资源,更大的问题就是这个方法会影响Scheduler的运作。

今天就写道这里:后续文章将会逐一讲解:Task的等待完成操作,Task中的异常处理,获取Task的状态,执行Lazily Task,常见问题解决方案。

原文标题:.NET 4 并行(多核)编程系列之四

链接:http://www.cnblogs.com/Leo_wl/archive/2010/06/01/1749597.html

【编辑推荐】

  1. 微软发布新版Windows 7及.NET 4软件开发工具包
  2. 详解.NET 4.0并行计算支持历史
  3. 详读.NET 4.0环境配置
  4. 详解.NET 4.0中异常处理方面的新特性
  5. 三方面诠释.NET 4.0的新特性

 

 

责任编辑:彭凡 来源: 博客园
相关推荐

2010-06-04 09:11:10

.NET并行编程

2010-06-07 08:43:46

.NET 4并行编程

2010-06-09 09:18:34

.NET 4并行编程

2010-06-02 08:53:51

.NET 4并行编程

2010-06-11 09:01:02

.NET 4并行编程

2011-03-24 09:23:43

.NET 4多核并行

2010-06-24 09:12:27

.NET 4并行编程

2015-10-13 09:18:00

.Net编程教程

2024-09-29 16:22:18

多线程TaskC#

2024-09-27 19:42:09

工具C#Task​

2024-04-07 09:04:18

Parallel 类编程工具.NET

2024-06-04 15:56:48

Task​.NET异步编程

2009-07-24 15:41:00

ASP.NET编程入门

2010-04-21 09:23:09

.NET 4

2017-04-25 15:20:11

Python进程mpi4py

2011-07-11 09:29:32

PHP面向对象编程

2012-04-10 10:04:26

并行编程

2009-02-23 15:20:03

SQL Server数据库ASP.NET

2023-10-30 08:57:19

.Net开发并行计算

2012-04-06 10:31:44

Java
点赞
收藏

51CTO技术栈公众号