Task.RunSynchronously有什么用?

时间:2018-10-11 12:02:23

标签: c# multithreading asynchronous

我只是想知道方法是什么?在哪种情况下我可以使用此方法。

我最初的想法是RunSynchronously是为了调用异步方法并同步运行该方法而不会引起像.wait()那样的死锁问题。

但是,根据MSDN

  

通常,任务在线程池线程上异步执行,并且不阻塞调用线程。通过调用RunSynchronously()方法执行的任务与当前TaskScheduler关联,并在调用线程上运行。如果目标调度程序不支持在调用线程上运行此任务,则该任务将按调度计划执行,并且调用线程将阻塞,直到任务完成执行为止。

如果任务要在调用线程上运行,为什么这里需要TaskScheduler?

2 个答案:

答案 0 :(得分:8)

RunSynchronously将何时启动任务的决定委托给当前的任务调度程序(或作为参数传递的任务调度程序)。

我不确定为什么要使用它(可能是内部使用或旧式使用),但是很难想到当前 .NET 版本中有用的用例。 @Fabjan has a possible explanation in his comment提问。

RunSynchronously要求调度程序同步运行它,但随后调度程序可以很好地忽略该提示,并在线程池线程中运行它,您当前的线程将同步阻塞,直到完成为止。

尽管我认为这是常见调度程序(ThreadPoolTask​​Scheduler和常见UI调度程序)上会发生的事情,但调度程序不必在当前线程上运行它,也不必立即运行它。

RunSynchronously也将引发异常,如果任务已经开始或已完成/已发生故障(这意味着您将无法在异步方法上使用它)。

此代码可以阐明不同的行为:

WaitResult根本不运行任务,它们只是在当前线程上等待任务完成并阻塞直到完成,因此,如果我们要进行比较,可以进行比较StartWaitRunSynchronously

class Scheduler : TaskScheduler
{
    protected override void QueueTask(Task task) => 
        Console.WriteLine("QueueTask");

    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
    {
        Console.WriteLine("TryExecuteTaskInline");

        return false;
    }

    protected override IEnumerable<Task> GetScheduledTasks() => throw new NotImplementedException();
}

static class Program
{
    static void Main()
    {
        var taskToStart = new Task(() => { });
        var taskToRunSynchronously = new Task(() => { });

        taskToStart.Start(new Scheduler());
        taskToRunSynchronously.RunSynchronously(new Scheduler());
    }
}

如果您尝试对Start或RunSynchronously进行注释并运行代码,则会看到Start尝试将任务排入调度程序,而RunSynchronously将尝试内联执行该任务并如果失败(返回false),它将排入队列。

答案 1 :(得分:3)

首先让我们看一下这段代码:

public async static Task<int> MyAsyncMethod()
{
   await Task.Delay(100);
   return 100;
}

//Task.Delay(5000).RunSynchronously();                        // bang
//Task.Run(() => Thread.Sleep(5000)).RunSynchronously();     // bang
// MyAsyncMethod().RunSynchronously();                      // bang

var t = new Task(() => Thread.Sleep(5000));
t.RunSynchronously();                                     // works

在此示例中,我们尝试在以下任务上调用RunSynchronously

  • 返回其他带有结果的任务(承诺任务)
  • 是一项“热门”任务
  • async await创建的另一个诺言任务
  • 具有委托人的“冷”任务

创建后它们将具有什么状态?

  • 等待激活
  • WaitingToRun
  • WaitingForActivation
  • 已创建

所有“热”任务均以状态WaitingForActivationWaitingToRun创建,并与任务计划程序相关联。

方法RunSynchronously仅知道如何处理包含委托且状态为Created的“冷”任务。

结论:

RunSynchronously方法可能是在没有“热门”任务或者它们没有被广泛使用并为特定目的而创建时出现的。

我们可能需要使用带有自定义TaskScheduler的“冷”任务时使用它,否则它就已经过时且无用。

要同步运行“热”任务(我们应该避免),我们可以使用task.GetAwaiter().GetResult()。作为奖励,它会返回原始异常,而不是AggregateException的实例。