【问题标题】:Why does exist a second parameter of `CancelationToken` type for Task.Run() method?为什么 Task.Run() 方法存在 `CancelationToken` 类型的第二个参数?
【发布时间】:2018-10-10 07:38:59
【问题描述】:

我试图理解对重载方法 Task.Run(Func, CancellationToken) 的需求。

为什么还存在CancelationToken类型的第二个参数,如果它甚至没有传递到Task.Run()方法的第一个参数中指定的函数中?我不得不在sum 函数代码中为此使用闭包。此外,我在 Microsoft 的代码示例中也看到了相同的内容(请查看上面的链接)。

这是我的代码:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadsLearning {
    class Program {

        private static void Main(string[] args) {

            CancellationTokenSource tokenSrc = new CancellationTokenSource();

            Func<int, int> sum = n => {
                int result = 0;

                for (var i = 0; i <= n; i++) {
                    result += i;

                    tokenSrc.Token.ThrowIfCancellationRequested();

                    Console.WriteLine(result);
                    Thread.Sleep(200);
                }
                return result;
            };

            /* Why does exist a second parameter of CancelationToken type, if it
             * is even not passed into the function specified in the first parameter
             * of Task.Run() method?
             * I'm forced to use a closure for this in the 'sum' function code.
             */
            var task = Task.Run(() => sum(30), tokenSrc.Token);

            // I will get the seame result for CancellationToken.None:
            // var task = Task.Run(() => sum(30), CancellationToken.None);

            tokenSrc.CancelAfter(TimeSpan.FromSeconds(2));

            try {
                Console.WriteLine("Result: {0}", task.Result);
            }
            catch (AggregateException ex) {
                foreach (var item in ex.InnerExceptions) {
                    Console.WriteLine("Exception: {0}", item.Message);
                }
            }
            catch (Exception ex) {
                Console.WriteLine("Other exception (the other 'catch' block): {0}", ex.Message);
            }

            Console.WriteLine("Hit <Enter> for exit...");
            Console.ReadLine();
        }
    }
}

【问题讨论】:

  • 您链接到的备注的第一句 - “如果在任务开始执行之前请求取消,任务不会执行。相反,它被设置为已取消状态并且引发 TaskCanceledException 异常。” (我的重点)

标签: c# .net scheduled-tasks


【解决方案1】:

有两个原因:

  • 如果在调用 Task.Run 时已请求取消,则传入 CancellationToken 可确保您的代码永远不会运行。
  • 如果您的代码从传入的同一CancellationToken 中抛出OperationCanceledException,则该任务将被标记为已取消而不是失败。其他代码可能会检查任务状态并相应地改变行为。

【讨论】:

  • 你是对的,当然。但我不明白为什么回调函数签名中没有CancellationToken……这种情况迫使我对这个实例使用闭包。在我看来这不好。
  • @AndreyBushman 对。您可以使用an overload of the Task constructorTaskFactory.StartNew 同上)传递任意数据,包括取消令牌的另一个副本。可惜没有对应的Task.Run重载。
猜你喜欢
  • 2013-07-08
  • 2022-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
  • 2020-02-11
  • 1970-01-01
  • 2019-11-25
相关资源
最近更新 更多