我有一个WPF应用程序,其中正在为并行处理生成大量任务。现在,当我的条件变为真时,我需要取消特定的任务。当我为取消任务应用CancellationTokenSource时,它将取消整个任务,但我只需要取消一个任务。
Task t1 = Task.Run(() => Task.Delay(30000, token), token);
test.Add(t1.Id, symbolName);
lstTask.Add(t1);
await t1;
我在这里持有任务ID,因此我知道应该取消哪个任务?
在讨论问题之后,我对代码进行了一些更改,因此请建议我应该更改逻辑吗?因为最近我知道任务ID不是唯一的,所以我更喜欢直接使用CTS。
public static async void startAddToPosition(System.Threading.CancellationTokenSource cts1, string symbolName)
{
try
{
Task t1 = Task.Run(() => Task.Delay(30000, cts1.Token), cts1.Token);
test.Add(symbolName, cts1);
lstTask.Add(t1);
lstCts.Add(cts1);
await t1;
generateRealPosition("QQQ"); //here I need symbol name when task will complete it's 30 seconds.
}
catch (OperationCanceledException ex)
{
var symbolName = test.FirstOrDefault(q => q.Value.Token == ex.CancellationToken).Key;
}
}
但是另一方面,当条件变为满时,我将尝试取消以下任务:
CancellationTokenSource cts = Evaluation.parallelScripts.test.FirstOrDefault(q => q.Key == eventData.symbolName).Value;
cts.Cancel();
因此,我尝试从列表中获取特定符号的CancellationTokenSource并取消该CTS。这样任务就取消了。
所以我的问题是我不知道CTS令牌是否唯一。因为当CTS取消Task时,在例外情况下,我需要根据该CTS令牌输入符号名称。
答案 0 :(得分:0)
您可以执行以下操作:
class Program
{
static void Main(string[] args)
{
Guid lastID = default(Guid);
List<CancellableTask> cancellableTasks = new List<CancellableTask>();
for (int i = 0; i < 10; i++)
{
CancellableTask task = new CancellableTask(() =>
{
Console.WriteLine("New task!");
Thread.Sleep(3000);
});
cancellableTasks.Add(task);
lastID = task.ID;
}
CancellableTask cancellableTask = cancellableTasks.FirstOrDefault(x => x.ID == lastID);
if (cancellableTask != null)
{
cancellableTask.Cancel();
}
}
}
public class CancellableTask
{
public Guid ID { get; private set; }
private CancellationTokenSource CancellationTokenSource { get; set; }
public Task Task { get; private set; }
public CancellableTask(Action action)
{
CancellationTokenSource = new CancellationTokenSource();
Task = Task.Run(action, CancellationTokenSource.Token);
ID = Guid.NewGuid();
}
public void Cancel()
{
CancellationTokenSource.Cancel();
}
}
答案 1 :(得分:0)
每个取消令牌源是一个单独的逻辑“取消”。如您所见,如果您共享取消令牌,那么一个“取消”将取消所有令牌。
要创建多个逻辑“取消”,您将需要多个取消令牌来源:
CancellationTokenSource cts1 = new CancellationTokenSource();
Task t1 = Task.Run(() => Task.Delay(30000, cts1.Token), cts1.Token);
test.Add(t1.Id, symbolName, cts1);
lstTask.Add(t1);
lstCts.Add(cts1);
await t1;
您能建议我怎样才能仅通过ID取消单个任务吗?
这不可能。
对于一个,不可能从“外部”取消任务。您所能做的就是给它一个令牌并取消该令牌。适当地响应该令牌取决于任务。 cooperative cancellation就是这样的。
还有另一个原因无法实现:task ids are not unique。看来您在代码中使用任务ID;我建议您重新评估设计,以确保它可以处理非唯一任务ID。也许改用实际的Task
实例(这是唯一的)。