.net 将CancellationToken作为参数传递给Task.Run有什么好处?

.net 将CancellationToken作为参数传递给Task.Run有什么好处?,.net,vb.net,task,task-parallel-library,cancellation,.net,Vb.net,Task,Task Parallel Library,Cancellation,显然,我意识到它使我能够取消任务,但这段代码实现了相同的效果,而无需将令牌传递到task.Run 实际的区别是什么?谢谢 Dim cts As New CancellationTokenSource Dim ct As CancellationToken = cts.Token Task.Run(Sub() For i = 1 To 1000 Debug.WriteLine(i) ct.ThrowIfC

显然,我意识到它使我能够取消任务,但这段代码实现了相同的效果,而无需将令牌传递到task.Run

实际的区别是什么?谢谢

Dim cts As New CancellationTokenSource
Dim ct As CancellationToken = cts.Token
Task.Run(Sub()
             For i = 1 To 1000
                 Debug.WriteLine(i)
                 ct.ThrowIfCancellationRequested()
                 Threading.Thread.Sleep(10)
             Next
         End Sub)

cts.CancelAfter(500)
VS

发言人说:

如果在任务开始执行之前请求取消,则任务不会执行。相反,它被设置为取消状态并引发TaskCanceledException异常

因此,在您的场景中,没有任何实际的区别,因为您在发出取消之前要等待500毫秒。在这段时间内,任务被调度,开始执行,并在发出取消之前在循环中运行多次,表现为从
ct.throwifcancellationrequest()
引发的异常

Task.Run(Action)
Task.Run(Action,CancellationToken)
之间的区别在您的示例的这个修改版本中更加明显:

Try
    Dim cts As New CancellationTokenSource
    Dim ct As CancellationToken = cts.Token

    cts.Cancel()

    Dim task As Task = Task.Run(
        Sub()
            Console.WriteLine("Started running your code!")
            ct.ThrowIfCancellationRequested()
            Console.WriteLine("Finished running your code!")
        End Sub, ct)

    task.Wait()

Catch ex As AggregateException
    Console.Error.WriteLine("Caught exception: " & ex.InnerException.Message)
End Try

Console.WriteLine("Done, press Enter to quit.")
Console.ReadLine()
在这种情况下,
Task.Run
会安排要运行的任务,但也会将取消令牌与该任务相关联。调用
task.Wait()
时,线程池在执行任务之前会检查取消令牌,并注意到该令牌已被取消,因此它决定在执行任务之前取消。因此,输出为:

Caught exception: A task was canceled.
Done, press Enter to quit.
Started running your code!
Caught exception: The operation was canceled.
Done, press Enter to quit.
如果将:
End-Sub,ct)
替换为
End-Sub)
,则线程池不知道取消令牌,因此即使您发出了取消,它也会在任务代码本身检查取消之前继续执行任务。因此,输出为:

Caught exception: A task was canceled.
Done, press Enter to quit.
Started running your code!
Caught exception: The operation was canceled.
Done, press Enter to quit.
(您可以看到,在这两种情况下,异常消息也略有不同。)


总之,向
Task.Run
方法提供取消令牌可以让线程池自己在线程池有机会执行任务之前知道任务是否已取消。这使得线程池可以节省时间和资源,甚至不必费心开始运行任务。

实际的区别是,如果令牌被取消,任务将处于什么状态

很抱歉这里的C代码

var cts=new CancellationTokenSource();
var withToken=Task.Run(回调,cts.Token);
var withoutToken=Task.Run(回调);
cts.Cancel();
void Callback()
{
睡眠(1000);
抛出新的OperationCanceledException(cts.Token);
}
尝试
{
Task.WaitAll(带令牌,不带令牌);
}
抓住
{
}
Console.WriteLine($“withToken.IsCanceled:{withToken.IsCanceled}”);
Console.WriteLine($”withToken.IsFaulted:{withToken.IsFaulted}”);
Console.WriteLine($”withToken.Status:{withToken.Status}”);
Console.WriteLine();
WriteLine($”withoutToken.IsCanceled:{withoutToken.IsCanceled}”);
Console.WriteLine($”withoutToken.IsFaulted:{withoutToken.IsFaulted}”);
Console.WriteLine($“withoutToken.Status:{withoutToken.Status}”);
该代码打印:

withToken.IsCanceled:True
withToken.IsFaulted:False
withToken。状态:已取消
withoutToken.IsCanceled:False
withoutToken.IsFaulted:True
withoutToken。状态:故障

这里的想法是,如果传递给
Task.Run
的回调抛出
OperationCanceledException
(或派生类型),则生成的
Task
将被标记为“Faulted”,除非异常的
CancellationToken
等于传递的令牌(在抛出异常时取消了
CancellationToken
).

在这种情况下,这没有多大区别,但很可能
任务的上下文无法访问令牌分配给的原始变量。例如,如果对象A创建了一个执行对象B方法的
任务
,B可能不知道A的存在,那么我怎么能t访问
CancellationToken
仅分配给?@jmchilinney Great point中的局部变量,我也在想同样的事情。在一个非琐碎的用例中,它的用途更加广泛。顺便说一句,你回答了我的许多问题,我非常感谢你的帮助jmchilinney