Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.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# 取消一个“长”;“字符串”;任务延续的正确性?强制任务执行顺序和线程使用情况?_C#_Task Parallel Library - Fatal编程技术网

C# 取消一个“长”;“字符串”;任务延续的正确性?强制任务执行顺序和线程使用情况?

C# 取消一个“长”;“字符串”;任务延续的正确性?强制任务执行顺序和线程使用情况?,c#,task-parallel-library,C#,Task Parallel Library,我有一个类,它将一小段IO工作串在一起,作为任务的延续。每次收到一件作品时,都会创建一个新的任务,然后将其作为LastCreatedTask的延续添加到该任务中。我正在尝试确定正确取消所有这些任务的方法 这是我目前的设置 private Task LastCreatedTask { get; set; } private CancellationTokenSource TaskQueueTokenSource { get; set; } public void ScheduleChunk(IO

我有一个类,它将一小段IO工作串在一起,作为
任务
的延续。每次收到一件作品时,都会创建一个新的
任务
,然后将其作为
LastCreatedTask
的延续添加到该任务中。我正在尝试确定正确取消所有这些
任务的方法

这是我目前的设置

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;
}
因此,在函数
schedulehunk
中,IO工作的“块”(以及超时)被传递给
CreateProcessTask
,后者创建了一个
Task
,该任务将执行IO工作的实际处理。一个
CancellationToken
被传递给该
任务,该任务是通过将两个
CancellationTokenSources
链接在一起完成的

第一个是“main”
CancellationTokenSource
;我希望能够简单地调用此源上的
Cancel
,以取消链接的所有
任务。第二个源是在给定时间段后自动取消的源(这将停止长时间运行/暂停的IO块)

最后,一旦构造的
任务
返回到
ScheduleChunk
中,它将作为延续添加到
LastCreatedTask
中,后者是最后一个作为延续添加的任务。这实际上使一系列的
任务
依次运行

1.我上面的方法是取消
任务链的正确方法吗?通过调用
TaskQueueTokenSource
上的
Cancel

2.是否使用了
TaskContinuationOptions。与continuations同步执行
是确保这些
Task
依次执行的正确方法

3.是否有办法指定我希望来自底层TPL
ThreadPool
的同一线程处理此
任务链


据我所知,不应该为每个延续点创建一个新线程,尽管在某个点上,一个新线程可能会拾取链。

使用传递给每个任务的共享取消令牌,而不是为每个任务创建一个唯一的取消令牌。当您取消该令牌时,使用该令牌的所有任务都将知道停止处理

您在我回答后进行了编辑,因此我将回答您的编号问题:

1.我的上述方法是否是取消任务链的正确方法?在TaskQueueTokenSource上调用Cancel

,最佳实践是创建一个令牌,然后将该令牌传递给每个任务

2.使用TaskContinuationOptions.Executes与continuations同步是否是确保这些任务按顺序依次执行的正确方法

不,您的任务应该是并行运行的,而最佳实践是让依赖顺序的任务在一个链上相互调用,第一个调用第二个,依此类推。或者,您可以等到第一个任务完成后再开始第二个任务

3.是否有办法指定我希望底层TPL线程池中的同一线程处理此任务链

您不太可能这样做,线程池和任务异步编程(TAP)以及TPL的部分目的是将显式线程抽象出来。在没有大量工作的情况下,无法保证运行任务的线程,甚至无法保证是否为该任务生成新线程


也就是说,如果出于某种原因确实需要执行此操作,那么现有代码根本不起作用:

LastCreatedTask.ContinueWith((t) => ioChunkProcessTask)
此继续操作仅返回一个任务,其结果将几乎立即设置为常量对象。这就是它的全部功能

实际上,这段代码的结构很笨拙。这样更好:

async Task RunProcessing() {
 while (...) {
  await CreateProcessTask(...);
 }
}
wait
用于对异步操作进行排序<代码>等待
在大多数情况下都可以替换
继续

取消看起来不错。也许它可以简化一点,但它工作得很好

关于3,你永远不应该需要这个。线程亲和力是一种罕见的东西,必须避免。没有办法完全按照要求做到这一点。请详细说明你想要实现的目标


如果您坚持使用Task.Run,下面是一个示意图:

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);

    return Task.Run(() => {
        inChunk.DoProcessing(ProcessTokenSource.Token);
    }, ProcessTokenSource.Token);
}

即使您在取消令牌上调用了
Cancel
,您仍然需要检查令牌是否已在所有任务中被取消。哦,是的,忘了在其中添加它。我马上就要编辑了。你能用wait吗?通常,所有任务链都应表示为异步方法。这使所有这些都变得容易。承认我缺乏知识,我不确定在这里使用async/await如何使这更容易?我对async/await有一定的理解,只是不理解它将如何应用。因此,我要回答的是,不,我不知道我是否可以或者我将如何做?我想这就是我使用
TaskQueueTokenSource
所做的。这与
CreateProcessTask
中的
ProcessTimeoutTokenSource
相结合,创建一个
CancellationTokenSource.Token
,传递给
任务
?我正在回答您在提交答案时提出的问题,但是根据MSDN,您只向所有任务传递一个令牌。我为您的三个明确问题添加了答案。链接到1的MSDN文章没有明确说明向每个任务传递相同令牌是最佳实践,这正是示例中的做法。另外,我“基本上”在做这个,不是吗?至于2的答案,这就是我目前正在做的。我将我的
任务与
ContinueWith
链接起来。据我所知,这有一种“把对方叫下一个链子”的效果