什么是Task.RunSynchronously?

Val*_*roM 13 c# multithreading asynchronous

我只是想知道方法是什么?在什么样的场景中我可以使用这种方法.

我最初的想法是RunSynchronously调用异步方法并同步运行它而不会造成死锁问题.wait().

但是,根据MSDN,

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

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

Ste*_*nio 8

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

我不确定它为什么存在(可能用于内部或遗留用途),但很难想象当前版本的.NET中有用的用例.@Fabjan在他对这个问题的评论中有一个可能的解释.

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您尝试并注释启动或RunSynchronously运行代码,您将看到Start尝试并将任务排入调度程序,同时RunSynchronously尝试内联执行它,如果失败(返回false),它将只排队.


Fab*_*jan 8

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

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
Run Code Online (Sandbox Code Playgroud)

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

  • 返回带有结果的其他任务(承诺任务)
  • 在线程池线程上运行的“热”委托任务
  • 创建的另一个承诺任务 async await
  • 与代表的“冷”任务

创建后会处于什么状态?

  • 等待激活
  • 等待运行
  • 等待激活
  • 已创建

所有“热门”和承诺任务都是使用状态WaitingForActivationWaitingToRun. 热任务还与任务调度程序相关联。

方法RunSynchronously只知道如何处理包含委托和状态的“冷”任务Created

结论:

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

我们可能希望在需要使用 custom 的“冷”任务时使用它TaskScheduler,否则它已经过时且毫无用处。

为了同步运行“热”任务(我们应该尽量避免),我们可以使用task.GetAwaiter().GetResult(). 这与它的工作原理相同,.Result但作为奖励,它返回原始异常而不是AggregateException. 尽管如此,'sync over async' 不是最好的选择,应该尽可能避免。