我有以下循环,可能会也可能不会动态创建一系列任务:
While(CreateNewTask == true)
{
if(isWorkerFree() && isValidJob() && isExecutable())
{
CancellationTokenSource cs = new CancellationTokenSource();
var myTask = Task.Run(() => Execute(cs.token);
}
}
现在,由于这些任务是动态创建的,我如何跟踪它们并取消特定任务或将取消令牌发送到特定任务?可能有6-7个任务在任何时间运行,我需要功能来知道哪些正在运行并取消特定的任务。
答案 0 :(得分:1)
您可以使用DTO跟踪每个此类任务:class Item { Task Task; CancellationTokenSource CTS; }
。保留这些项目的列表。然后你可以随意取消它们。
答案 1 :(得分:1)
<强> TL; DR; 强>
我认为TPL Dataflow(https://msdn.microsoft.com/en-us/library/hh228603(v=vs.110).aspx)是一个更好的选择,但我会用TPL回答
<强>答案强>
要限制并发性,您需要的是一个限制并发性的调度程序。我建议您查看https://msdn.microsoft.com/library/system.threading.tasks.taskscheduler.aspx并搜索LimitedConcurrencyLevelTaskScheduler。
以下代码是您尝试实现的一个简单示例。
[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模式不适用于Scheduler的AttachToParent选项,或者此代码可能更加干净。请参阅:TaskCreationOptions.AttachedToParent is not waiting for child task
要管理CancellationTokens,您可以创建一个允许这样的特定TaskFactory:
taskFactory.StartNew(0 , () => {...});
taskFactory.Cancel(0);
任何TaskFactory方法都不是虚拟的,因此您必须创建重载方法。