栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

实施永无止境的任务的正确方法。(计时器与任务)

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

实施永无止境的任务的正确方法。(计时器与任务)

我将为此使用TPL
Dataflow
(因为您使用的是.NET
4.5,并且它在

Task
内部使用)。您可以轻松地创建一个
ActionBlock<TInput>
在处理完操作并等待适当时间后将项目发布到其自身的对象。

首先,创建一个工厂,该工厂将创建您永无止境的任务:

ITargetBlock<DateTimeOffset> CreateNeverEndingTask(    Action<DateTimeOffset> action, CancellationToken cancellationToken){    // Validate parameters.    if (action == null) throw new ArgumentNullException("action");    // Declare the block variable, it needs to be captured.    ActionBlock<DateTimeOffset> block = null;    // Create the block, it will call itself, so    // you need to separate the declaration and    // the assignment.    // Async so you can wait easily when the    // delay comes.    block = new ActionBlock<DateTimeOffset>(async now => {        // Perform the action.        action(now);        // Wait.        await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken). // Doing this here because synchronization context more than // likely *doesn't* need to be captured for the continuation // here.  As a matter of fact, that would be downright // dangerous. ConfigureAwait(false);        // Post the action back to the block.        block.Post(DateTimeOffset.Now);    }, new ExecutionDataflowBlockOptions {         CancellationToken = cancellationToken    });    // Return the block.    return block;}

我选择了

ActionBlock<TInput>
一个
DateTimeOffset
结构 ;
您必须传递一个类型参数,它也可能传递一些有用的状态(可以根据需要更改状态的性质)。

另外,请注意,

ActionBlock<TInput>
默认情况下,一次只能处理 一项
,因此可以确保只处理一项操作(这意味着,当它再次调用扩展方法时,您不必处理重入)。
Post

我还将该

CancellationToken
结构传递给的构造函数
ActionBlock<TInput>
Task.Delay
方法调用;如果取消了该过程,则取消将在第一个可能的机会发生。

从那里,可以轻松地重构代码来存储实现的

ITargetBlock<DateTimeoffset>
接口
ActionBlock<TInput>
(这是代表作为使用者的块的高级抽象,并且您希望能够通过调用
Post
扩展方法来触发使用):

CancellationTokenSource wtoken;ActionBlock<DateTimeOffset> task;

您的

StartWork
方法:

void StartWork(){    // Create the token source.    wtoken = new CancellationTokenSource();    // Set the task.    task = CreateNeverEndingTask(now => DoWork(), wtoken.Token);    // Start the task.  Post the time.    task.Post(DateTimeOffset.Now);}

然后你的

StopWork
方法:

void StopWork(){    // CancellationTokenSource implements IDisposable.    using (wtoken)    {        // Cancel.  This will cancel the task.        wtoken.Cancel();    }    // Set everything to null, since the references    // are on the class level and keeping them around    // is holding onto invalid state.    wtoken = null;    task = null;}

您为什么要在这里使用TPL Dataflow?原因如下:

关注点分离

CreateNeverEndingTask
现在,该方法是一家工厂,可以创建您的“服务”。您可以控制它的启动和停止时间,它是完全独立的。您不必将计时器的状态控制与代码的其他方面交织在一起。您只需创建块,然后启动它,然后在完成时停止它即可。

更有效地使用线程/任务/资源

对于

Task
线程池,TPL数据流中块的默认调度程序是相同的。通过使用
ActionBlock<TInput>
来处理您的操作以及对的调用
Task.Delay
,您可以在实际上不执行任何操作的情况下控制所使用的线程。当然,当您生成新的
Task
将继续处理的代码时,这实际上会导致一些开销,但是考虑到您不是在紧密的循环中进行处理(每次调用之间要等待十秒钟),所以这应该很小。

如果

DoWork
实际上可以使该函数处于等待状态(即,该函数返回a
Task
),那么您可以(可能)通过调整上面的factory方法采用a
Func<DateTimeOffset, CancellationToken,Task>
而不是来优化此效果
Action<DateTimeOffset>
,如下所示:

ITargetBlock<DateTimeOffset> CreateNeverEndingTask(    Func<DateTimeOffset, CancellationToken, Task> action,     CancellationToken cancellationToken){    // Validate parameters.    if (action == null) throw new ArgumentNullException("action");    // Declare the block variable, it needs to be captured.    ActionBlock<DateTimeOffset> block = null;    // Create the block, it will call itself, so    // you need to separate the declaration and    // the assignment.    // Async so you can wait easily when the    // delay comes.    block = new ActionBlock<DateTimeOffset>(async now => {        // Perform the action.  Wait on the result.        await action(now, cancellationToken). // Doing this here because synchronization context more than // likely *doesn't* need to be captured for the continuation // here.  As a matter of fact, that would be downright // dangerous. ConfigureAwait(false);        // Wait.        await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken). // Same as above. ConfigureAwait(false);        // Post the action back to the block.        block.Post(DateTimeOffset.Now);    }, new ExecutionDataflowBlockOptions {         CancellationToken = cancellationToken    });    // Return the block.    return block;}

当然,将

CancellationToken
通孔编织到您的方法(如果它接受一种方法)将是一个好习惯,这是在这里完成的。

这意味着您将拥有一个

DoWorkAsync
具有以下签名的方法:

Task DoWorkAsync(CancellationToken cancellationToken);

您必须更改方法(只需稍作更改,并且这里不会泄漏关注点的分离),

StartWork
以说明传递给该
CreateNeverEndingTask
方法的新签名的方法,如下所示:

void StartWork(){    // Create the token source.    wtoken = new CancellationTokenSource();    // Set the task.    task = CreateNeverEndingTask((now, ct) => DoWorkAsync(ct), wtoken.Token);    // Start the task.  Post the time.    task.Post(DateTimeOffset.Now, wtoken.Token);}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/432997.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号