博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.NET 4 并行(多核)编程系列之四 Task的休眠
阅读量:6162 次
发布时间:2019-06-21

本文共 4955 字,大约阅读时间需要 16 分钟。

  hot3.png

.NET 4 并行(多核)编程系列之四 Task的休眠

前言:之前的几篇文章断断续续的介绍了Task的一些功能:创建,取消。本篇介绍Task的休眠,本篇的内容比较的少。

本篇的议题如下:

1.       Task的休眠。

 

系列文章链接:

 

 

 

 

 

 

1. Task的休眠

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

下面就讲讲休眠的方法:

 

a.       使用CancellationTokenWait Handle

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

 

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

下面来看一段示例代码:

09130438_GjnQ.gif
代码
        
static
 
void
 Main(
string
[] args)
        {
            
//
 create the cancellation token source
            CancellationTokenSource tokenSource 
=
 
new
 CancellationTokenSource();
            
//
 create the cancellation token
            CancellationToken token 
=
 tokenSource.Token;
            
//
 create the first task, which we will let run fully
            Task task1 
=
 
new
 Task(() 
=>
            {
                
for
 (
int
 i 
=
 
; i 
<
 Int32.MaxValue; i
++
)
                {
                    
//
 put the task to sleep for 10 seconds
                    
bool
 cancelled 
=
 token.WaitHandle.WaitOne(
10000
);
                    
//
 print out a message
                    Console.WriteLine(
"
Task 1 - Int value {0}. Cancelled? {1}
"
,
                    i, cancelled);
                    
//
 check to see if we have been cancelled
                    
if
 (cancelled)
                    {
                        
throw
 
new
 OperationCanceledException(token);
                    }
                }
            }, token);
            
//
 start task
            task1.Start();
            
//
 wait for input before exiting
            Console.WriteLine(
"
Press enter to cancel token.
"
);
            Console.ReadLine();
            
//
 cancel the token
            tokenSource.Cancel();
            
//
 wait for input before exiting
            Console.WriteLine(
"
Main method complete. Press enter to finish.
"
);
            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类型的参数,表示要休眠多长时间。

 

 

09130438_GjnQ.gif
代码
 
static
 
void
 Main(
string
[] args)
        {
            
//
 create the cancellation token source
            CancellationTokenSource tokenSource 
=
 
new
 CancellationTokenSource();
            
//
 create the cancellation token
            CancellationToken token 
=
 tokenSource.Token;
            
//
 create the first task, which we will let run fully
            Task task1 
=
 
new
 Task(() 
=>
            {
                
for
 (
int
 i 
=
 
; i 
<
 Int32.MaxValue; i
++
)
                {
                    
//
 put the task to sleep for 10 seconds
                    Thread.Sleep(
10000
);
                    
//
 print out a message
                    Console.WriteLine(
"
Task 1 - Int value {0}
"
, i);
                    
//
 check for task cancellation
                    token.ThrowIfCancellationRequested();
                }
            }, token);
            
//
 start task
            task1.Start();
            
//
 wait for input before exiting
            Console.WriteLine(
"
Press enter to cancel token.
"
);
            Console.ReadLine();
            
//
 cancel the token
            tokenSource.Cancel();
            
//
 wait for input before exiting
            Console.WriteLine(
"
Main method complete. Press enter to finish.
"
);
            Console.ReadLine();
        }

这种方法和之前第一种方法最大的区别就是:使用Thread.Sleep()之后,然后再调用tokencancel方法,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的轮转关联起来,我们还是用代码示例讲解吧。

 

09130438_GjnQ.gif
代码
    
static
 
void
 Main(
string
[] args)
        {
            
//
 create the cancellation token source
            CancellationTokenSource tokenSource 
=
 
new
 CancellationTokenSource();
            
//
 create the cancellation token
            CancellationToken token 
=
 tokenSource.Token;
            
//
 create the first task, which we will let run fully
            Task task1 
=
 
new
 Task(() 
=>
            {
                
for
 (
int
 i 
=
 
; i 
<
 Int32.MaxValue; i
++
)
                {
                    
//
 put the task to sleep for 10 seconds
                    Thread.SpinWait(
10000
);
                    
//
 print out a message
                    Console.WriteLine(
"
Task 1 - Int value {0}
"
, i);
                    
//
 check for task cancellation
                    token.ThrowIfCancellationRequested();
                }
            }, token);
            
//
 start task
            task1.Start();
            
//
 wait for input before exiting
            Console.WriteLine(
"
Press enter to cancel token.
"
);
            Console.ReadLine();
            
//
 cancel the token
            tokenSource.Cancel();
            
//
 wait for input before exiting
            Console.WriteLine(
"
Main method complete. Press enter to finish.
"
);
            Console.ReadLine();
        }

 

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

 

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

  版权为小洋和博客园所有,转载请标明出处给作者。

http://www.cnblogs.com/yanyangtian

 

 

 

原文链接:

转载于:https://my.oschina.net/dtec/blog/43560

你可能感兴趣的文章
利用FIFO进行文件拷贝一例
查看>>
Ecshop安装过程中的的问题:cls_image::gd_version()和不支持JPEG
查看>>
resmgr:cpu quantum等待事件
查看>>
一个屌丝程序猿的人生(六十六)
查看>>
Java 编码 UTF-8
查看>>
SpringMVC实战(注解)
查看>>
关于静态属性和静态函数
查看>>
进程的基本属性:进程ID、父进程ID、进程组ID、会话和控制终端
查看>>
spring+jotm+ibatis+mysql实现JTA分布式事务
查看>>
MyBatis启动:MapperStatement创建
查看>>
调查问卷相关
查看>>
eclipse启动无响应,老是加载不了revert resources,或停留在Loading workbench状态
查看>>
1. Git-2.12.0-64-bit .exe下载
查看>>
怎样关闭“粘滞键”?
查看>>
[转]React 教程
查看>>
拓扑排序介绍
查看>>
eclipse打开工作空间(workspace)没有任务反应
查看>>
使用Sybmol模块来构建神经网络
查看>>
字符串去分割符号
查看>>
WPF中,多key值绑定问题,一个key绑定一个界面上的对象
查看>>