Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用CancellationToken取消特定任务_C#_.net_Task - Fatal编程技术网

C# 使用CancellationToken取消特定任务

C# 使用CancellationToken取消特定任务,c#,.net,task,C#,.net,Task,我有以下循环,可以动态创建一系列任务,也可以不动态创建一系列任务: While(CreateNewTask == true) { if(isWorkerFree() && isValidJob() && isExecutable()) { CancellationTokenSource cs = new CancellationTokenSource(); var myTask = Task.Run(() => Execute(cs.tok

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

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

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

您可以使用DTO:
类项{task task;CancellationTokenSource CTS;}
跟踪每个这样的任务。保留这些项目的列表。然后你可以随意取消它们。

TL;博士
我认为TPL数据流()在这里是一个更好的选择,但我将使用TPL来回答

回答
要限制并发性,需要一个限制并发性的调度器。我建议您查看并搜索LimitedConcurrencyLevel TaskScheduler

下面的代码是您试图实现的一个简单示例

[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个并发任务

不幸的是,TAP模式不能与调度器的AttachToParent选项一起使用,或者此代码可能更干净。见:

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

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

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

如何确定要取消的方法?那么,如何将
CreateNewTask
设置为false?@JonSkeet while循环正在查看队列,如果队列中有新任务,它会将“CreateNewTask”设置为true。我希望同时运行最多7个任务(工作人员)。对于队列中的每个项目,我们创建一个任务,并执行该任务。这项任务可能需要几分钟到几小时的时间来完成。因此,我希望能够取消正在运行的任务。现在,正如您概述的那样,我面临两个挑战:a)随时获取正在运行的任务列表,b)取消特定任务。我真的很感谢你的帮助。你还没有说如何指定要取消哪一个。听起来你应该看看TPL数据流:@JonSkeet谢谢你Jon,理想情况下管理员会通过服务发送取消任务的请求。这并不能真正回答我的问题-你正在启动任务,你想取消其中一项任务。。。您希望如何知道取消哪个任务?@user2972161是一个“数据传输对象”。只包含一些字段的哑类。我不确定你对ActionBlock有什么特别的想法。我有一个ActionBlock,可以同时运行多达16个任务,但我希望能够以某种方式附加一个取消令牌列表,以便可以取消这16个任务中的任何一个。操作块是我的TPL数据流管道的一部分。似乎没有我想做什么的例子,但我不能是第一个想做这件事的人。@user2972161您可以将CancellationToken与要处理的数据一起传递到操作块中。然后,ActionBlock中的代码需要遵守CancellationToken并取消自身。