使用CancellationToken取消特定任务 [英] Cancel Specific Task using CancellationToken

查看:104
本文介绍了使用CancellationToken取消特定任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下循环,可能会或可能不会动态创建一系列任务:

I have the following Loop which may or may not create a series of tasks dynamically:

While(CreateNewTask == true)
{
 if(isWorkerFree() && isValidJob() && isExecutable())
 {
   CancellationTokenSource cs = new  CancellationTokenSource();
   var myTask = Task.Run(() => Execute(cs.token);
 }
}

现在,由于这些任务是动态创建的,我如何跟踪它们并取消特定任务或向特定任务发送取消令牌?随时可能有6-7个任务在运行,我需要该功能才能知道正在运行的任务并取消特定任务.

Now since these tasks are created dynamically, how can I track them and cancel a specific task or send a cancellation token to a specific task? There may be 6-7 tasks running at any time, I need the functionality to know which ones are running and cancel a specific one.

推荐答案

TL; DR;
我认为TPL数据流( https://msdn.microsoft.com/en-us/library/hh228603(v=vs.110).aspx )是一个更好的选择,但我会使用TPL回答

TL;DR;
I think that the TPL Dataflow (https://msdn.microsoft.com/en-us/library/hh228603(v=vs.110).aspx) is a better choice here but I will answer using the TPL

答案
要限制并发性,您需要的是一个限制并发性的调度程序.我建议您查看 https://msdn.microsoft.com/library/system.threading.tasks.taskscheduler.aspx 并搜索LimitedConcurrencyLevelTask​​Scheduler.

Answer
To limit the concurrency, what you need is a scheduler that limits concurrency. I suggest that you look at https://msdn.microsoft.com/library/system.threading.tasks.taskscheduler.aspx and search for LimitedConcurrencyLevelTaskScheduler.

下面的代码是您要实现的目标的简单示例.

The code below is a simple example of what you are trying to achieve.

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public async Task TestMethod1()
    {
        var factoryCancellation = new CancellationTokenSource();
        var scheduler = new LimitedConcurrencyLevelTaskScheduler(maxDegreeOfParallelism: 7);
        var taskFactory = new TaskFactory(factoryCancellation.Token, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler);

        var taskCancellation1 = new CancellationTokenSource();
        var taskCancellation2 = new CancellationTokenSource();
        var token1 = taskCancellation1.Token;
        var token2 = taskCancellation2.Token;

        var myTask1 = taskFactory.StartNew(async () => await Execute(0, token1), token1).Unwrap();
        var myTask2 = taskFactory.StartNew(async () => await Execute(1, token2), token2).Unwrap();

        taskCancellation1.CancelAfter(500);

        try
        {
            await Task.WhenAll(myTask1, myTask2);
        }
        catch
        {
            //ThrowIfCancellationRequested Exception
        }
    }

    private async Task Execute(int i, CancellationToken token)
    {
        Console.WriteLine($"Running Task {i} : Before Delay 1");
        await Task.Delay(1000);
        token.ThrowIfCancellationRequested();
        Console.WriteLine($"Running Task {i} : Before Delay 2");
        await Task.Delay(1000);
        token.ThrowIfCancellationRequested();
        Console.WriteLine($"Running Task {i} : Before Delay 3");
        await Task.Delay(1000);
        token.ThrowIfCancellationRequested();
    }
}

这将生成以下日志

QueueTask 1  WaitingToRun
QueueTask 2  WaitingToRun
TryExecuteTask Start 1  WaitingToRun CreationOptions None
TryExecuteTask Start 2  WaitingToRun CreationOptions None
Running Task 1 : Before Delay 1
Running Task 0 : Before Delay 1
TryExecuteTask End 2 RanToCompletion IsCanceled False IsCompleted True IsFaulted False
TryExecuteTask End 1 RanToCompletion IsCanceled False IsCompleted True IsFaulted False
TryExecuteTaskInline Start 5 taskWasPreviouslyQueued False
TryExecuteTaskInline End 5 WaitingToRun IsCanceled False IsCompleted False IsFaulted False
QueueTask 5 System.Action WaitingToRun
TryExecuteTask Start 5 System.Action WaitingToRun CreationOptions None
Running Task 1 : Before Delay 2
TryExecuteTask End 5 RanToCompletion IsCanceled False IsCompleted True IsFaulted False
TryExecuteTaskInline Start 6 taskWasPreviouslyQueued False
TryExecuteTaskInline End 6 WaitingToRun IsCanceled False IsCompleted False IsFaulted False
QueueTask 6 System.Action WaitingToRun
TryExecuteTask Start 6 System.Action WaitingToRun CreationOptions None
TryExecuteTaskInline Start 8 taskWasPreviouslyQueued False
TryExecuteTaskInline End 8 RanToCompletion IsCanceled False IsCompleted True IsFaulted False
TryExecuteTask End 6 RanToCompletion IsCanceled False IsCompleted True IsFaulted False
TryExecuteTaskInline Start 12 taskWasPreviouslyQueued False
TryExecuteTaskInline End 12 WaitingToRun IsCanceled False IsCompleted False IsFaulted False
QueueTask 12 System.Action WaitingToRun
TryExecuteTask Start 12 System.Action WaitingToRun CreationOptions None
Running Task 1 : Before Delay 3
TryExecuteTask End 12 RanToCompletion IsCanceled False IsCompleted True IsFaulted False
TryExecuteTaskInline Start 14 taskWasPreviouslyQueued False
TryExecuteTaskInline End 14 WaitingToRun IsCanceled False IsCompleted False IsFaulted False
QueueTask 14 System.Action WaitingToRun
TryExecuteTask Start 14 System.Action WaitingToRun CreationOptions None
TryExecuteTaskInline Start 16 taskWasPreviouslyQueued False
TryExecuteTaskInline End 16 RanToCompletion IsCanceled False IsCompleted True IsFaulted False
TryExecuteTask End 14 RanToCompletion IsCanceled False IsCompleted True IsFaulted False

您可以看到任务0尽快被取消,任务1继续处理.此示例未显示,但绝不会超过7个并发任务.

You can see that the Task 0 is cancelled as soon as possible and Task 1 continue to process. This example does not show but will never be more than 7 concurrent tasks.

不幸的是,TAP模式不能与Scheduler的AttachToParent选项一起使用,否则此代码可能会更干净.请参阅:TaskCreationOptions.AttachedToParent不等待子任务

Unfortunately the TAP pattern does not works with the AttachToParent option of the Scheduler, or this code could be even more clean. See: TaskCreationOptions.AttachedToParent is not waiting for child task

要管理CancellationToken,您可以创建一个特定的TaskFactory来允许以下操作:

And to manage the CancellationTokens you can create a specific TaskFactory that allows something like this:

taskFactory.StartNew(0 , () => {...});
taskFactory.Cancel(0);

TaskFactory方法都不是虚拟的,因此您必须创建重载方法.

None of the TaskFactory methods are virtual so you will have to create overloaded method.

这篇关于使用CancellationToken取消特定任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆