我有一个类将小块IO工作串起来作为Task
个续点。每次收到一件作品时,都会创建一个新的Task
,然后将其作为LastCreatedTask
的续篇添加。我正在尝试确定正确取消所有这些Task
的正确方法吗?
这是我目前的设置
private Task LastCreatedTask { get; set; }
private CancellationTokenSource TaskQueueTokenSource { get; set; }
public void ScheduleChunk(IOWorkChunk inChunk, int procTimeout)
{
Task ioChunkProcessTask = CreateProcessTask(inChunk, procTimeout);
LastCreatedTask.ContinueWith(
(t) => ioChunkProcessTask.Start(),
TaskContinuationOptions.ExecuteSynchronously);
LastCreatedTask = ioChunkProcessTask;
}
private Task CreateProcessTask(IOWorkChunk inChunk, int procTimeout)
{
// Create a TokenSource that will cancel after a given timeout period
var ProcessTimeoutTokenSource = new CancellationTokenSource(
TimeSpan.FromSeconds(procTimeout));
// Create a TokenSource for the Task that is a
// link between the timeout and "main" token source
var ProcessTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
TaskQueueTokenSource.Token,
ProcessTimeoutTokenSource.Token);
// Create a Task that will do the actual processing
Task ioChunkProcessTask = new Task(() =>
{
if(!ProcessTokenSource.Token.IsCancellationRequested)
inChunk.DoProcessing(ProcessTokenSource.Token);
}, ProcessTokenSource.Token);
return ioChunkProcessTask;
}
所以在函数ScheduleChunk
a" chunk"将IO工作(和超时)传递给CreateProcessTask
,这将创建一个Task
,用于执行IO工作的实际处理。 CancellationToken
传递给此Task
,这是通过将两个CancellationTokenSources
链接在一起而制作的。
第一个是"主要" CancellationTokenSource
;我希望能够简单地在此来源上调用Cancel
来取消链接的所有Task
。第二个源是在一段给定的时间后自动取消的源(这将停止长时间运行/停止的IO块)。
最后,一旦构造的Task
返回到ScheduleChunk
,它就会被添加为LastCreatedTask
的延续,这是作为延续添加的最后一个任务。这实际上使Task
链一个接一个地运行。
1。 我的方法是否取消Task
链的正确方法?致电Cancel
上的TaskQueueTokenSource
2。 是否正确使用TaskContinuationOptions.ExecuteSynchronously
和continuation以确保这些Task
按顺序依次执行?< / em>
3。 有没有办法指定我希望基础TPL ThreadPool
中的同一个线程能够在Task
链上工作?< / em>
据我所知,不应该为每个延续点创建一个新线程,尽管在某些时候新线程可以拾取链。
答案 0 :(得分:2)
现有代码根本不起作用:
LastCreatedTask.ContinueWith((t) => ioChunkProcessTask)
此延续只返回一个任务,其结果几乎立即被设置为一个常量对象。这就是全部。
实际上,这段代码的结构很笨拙。这要好得多:
async Task RunProcessing() {
while (...) {
await CreateProcessTask(...);
}
}
await
用于对异步操作进行排序。 <{1}}可以在大多数时间内取代await
。
取消看起来不错。也许它可以简化一点,但它工作正常。
关于3,你永远不需要这个。线程亲和力是一种罕见的事情,需要避免。没有办法完全按照要求这样做。请详细说明你想要达到的目标。
如果你坚持使用Task.Run,这里有一个草图:
ContinueWith
答案 1 :(得分:0)
使用您传递给每个任务的共享取消令牌,而不是为每个任务创建唯一的令牌。取消该令牌后,使用该令牌的所有任务将知道停止处理。
我回答后编辑了,所以我会回复您的个别编号问题:
1。 我的方法是否正确取消任务链?通过在TaskQueueTokenSource上调用Cancel?
According to msdn,最佳做法是创建一个令牌,然后将相同的令牌传递给每个任务。
2. 是否正确使用TaskContinuationOptions.ExecuteSynchron和continuation正确的方法来确保这些Task一个接一个地执行?
不,你的任务是要并行运行的,最好的做法是让依赖于命令的任务在链中相互调用,第一个调用第二个,依此类推。或者,您可以等到第一个任务完成后再开始第二个任务。
3. 有没有办法指定我希望底层TPL ThreadPool中的同一个线程能够在这个Task链上工作?
你不太可能这样做,这是线程池和任务异步编程(TAP)的目的的一部分,而TPL是抽象显式线程。您无法保证运行任务的线程,甚至无法在没有大量工作的情况下为该任务生成新线程。
那就是说,如果由于某种原因你确实需要这样做a custom task scheduler is the answer