Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.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# 为什么不是';t任务中包含的CancellationToken<;T>;蒙纳德?_C#_F#_Task Parallel Library_Async Await_Monads - Fatal编程技术网

C# 为什么不是';t任务中包含的CancellationToken<;T>;蒙纳德?

C# 为什么不是';t任务中包含的CancellationToken<;T>;蒙纳德?,c#,f#,task-parallel-library,async-await,monads,C#,F#,Task Parallel Library,Async Await,Monads,Task巧妙地保存了一个“has start,maybe finished”计算,该计算可以与其他任务组成,映射函数等。相反,F#monad保存了一个“可能稍后启动,可能正在运行”计算,以及一个CancellationToken。在C#中,您通常必须将CancellationToken线程化到与任务一起工作的每个函数中。为什么C#团队选择将计算封装在任务单子中,而不是取消令牌?任务最初用于包含类中的附加功能,但后来被更改为使用附加功能支持聚合对象。这一切都是为了表现 (参见论文中的“重组任务”)

Task
巧妙地保存了一个“has start,maybe finished”计算,该计算可以与其他任务组成,映射函数等。相反,F#monad保存了一个“可能稍后启动,可能正在运行”计算,以及一个
CancellationToken
。在C#中,您通常必须将
CancellationToken
线程化到与
任务一起工作的每个函数中。为什么C#团队选择将计算封装在
任务
单子中,而不是
取消令牌

任务最初用于包含类中的附加功能,但后来被更改为使用附加功能支持聚合对象。这一切都是为了表现

(参见论文中的“重组任务”)Joseph E.Hoag的论文对.NET 4.5中的优化提供了很好的见解。我相信,对于任何试图从async/Wait中挤出最后10%的性能的人来说,这本书都是值得一读的

我假设在决定如何打包取消功能时也应用了类似的思维过程


我不能代表C#或团队说话,但我认为这是一种性能优化,要么只能在F#编译器中实现,要么性能对F#团队无关紧要

或多或少,他们封装了
CancellationToken
对于C#
async
方法的隐式使用。考虑这一点:

var cts = new CancellationTokenSource();
cts.Cancel();
var token = cts.token;

var task1 = new Task(() => token.ThrowIfCancellationRequested());
task1.Start();
task1.Wait(); // task in Faulted state

var task2 = new Task(() => token.ThrowIfCancellationRequested(), token);
task2.Start();
task2.Wait(); // task in Cancelled state

var task3 = (new Func<Task>(async() => token.ThrowIfCancellationRequested()))();
task3.Wait(); // task in Cancelled state
var cts=new CancellationTokenSource();
cts.Cancel();
var-token=cts.token;
var task1=新任务(()=>token.ThrowIfCancellationRequested());
task1.Start();
task1.Wait();//任务处于错误状态
var task2=新任务(()=>token.ThrowIfCancellationRequested(),token);
task2.Start();
task2.Wait();//处于取消状态的任务
var task3=(新函数(异步()=>token.ThrowIfCancellationRequested())();
task3.Wait();//处于取消状态的任务
对于非异步lambda,我必须显式地将
令牌
task2
关联,以便通过将其作为参数提供给
newtask()
(或
Task.Run
)来正确传播取消。对于与
task3
一起使用的
async
lambda,它作为
async/await
基础结构代码的一部分自动发生

此外,对于
异步
方法,任何
标记都会传播取消,而对于非异步计算
新任务()
/
任务。Run
lambda,它必须是传递给任务构造函数或
任务的相同标记。Run

当然,我们仍然需要手动调用
token.ThrowIfCancellationRequested()
来实现协作取消模式。我无法回答为什么C#和TPL团队决定以这种方式实现它,但我想他们的目的是不使
async/await
的语法过于复杂,同时保持足够的灵活性


至于F#,我还没有看过异步工作流生成的IL代码,如Tomas Petricek的《you linked》中所示。然而,据我所知,令牌仅在工作流的某些位置自动测试,这些位置对应于C#中的
await
(通过类比,我们可能在C#中的每次
await
之后手动调用
token.throwifccancellationrequest()
)。这意味着任何CPU限制的工作仍然不会立即取消。否则,F#必须在每个IL指令之后发出
令牌。throwifcancellationrequest()
,这将是相当大的开销。

在C#中,您有“可以稍后启动,现在可能正在运行”计算,以及
var task=new task(操作,令牌)形式的CancellationToken选项
。我忘了那张白纸了。驱动器似乎是为了使任务对象本身尽可能小,因此没有携带取消令牌,而是在由async/await生成的状态机中携带它。何时以及为什么要使用async/await进行CPU绑定的工作?@GregC,任何时候我需要在UI应用程序中执行CPU限制的工作:
var pi=wait Task.Run(()=>CalcPi(digits,token),token)
@GregC作为并行化的一种形式<代码>等待任务。当所有(任务)
@GregC时,我宁愿将
IEnumerable
IObservable
(Rx的一项功能,与TPL的
任务
)进行比较。我想链接Thomas P的一个例外解释