web-dev-qa-db-fra.com

À quoi sert Task.RunSynchronously?

Je me demande juste à quoi sert la méthode? Dans quel genre de scénario je peux utiliser cette méthode.

Ma pensée initiale est RunSynchronously est d'appeler une méthode asynchrone et de l'exécuter de manière synchrone sans provoquer de problème de blocage comme ce que fait .wait().

Cependant, selon MSDN ,

En règle générale, les tâches sont exécutées de manière asynchrone sur un thread de pool de threads et ne bloquent pas le thread appelant. Les tâches exécutées en appelant la méthode RunSynchronously () sont associées au TaskScheduler en cours et sont exécutées sur le thread appelant. Si le planificateur cible ne prend pas en charge l'exécution de cette tâche sur le thread appelant, la tâche sera planifiée pour exécution selon la planification et le thread appelant se bloquera jusqu'à ce que la tâche soit terminée.

Pourquoi avoir besoin d'un TaskScheduler ici, si la tâche va s'exécuter sur le thread appelant?

13
ValidfroM

RunSynchronously délègue la décision de démarrer la tâche au planificateur de tâches en cours (ou celui passé en argument).

Je ne sais pas pourquoi il est là (peut-être pour une utilisation interne ou héritée), mais il est difficile de penser à un cas d'utilisation utile dans les versions actuelles de . NET . @ Fabjan a une explication possible dans son commentaire à la question.

RunSynchronously demande au planificateur de l'exécuter de manière synchrone, mais le planificateur pourrait très bien ignorer l'indice et l'exécuter dans un thread de pool de threads et votre thread actuel se bloquera de manière synchrone jusqu'à ce qu'il soit terminé.

Le planificateur ne doit pas l'exécuter sur le thread actuel et ne doit pas l'exécuter immédiatement, même si je pense que c'est ce qui se passera sur les planificateurs communs (ThreadPoolTaskScheduler et les planificateurs d'interface utilisateur communs).

RunSynchronously lèvera également une exception si la tâche a déjà été démarrée ou est terminée/défectueuse (cela signifie que vous ne pourrez pas l'utiliser sur les méthodes asynchrones).

Ce code peut clarifier les différents comportements:

Wait et Result n'exécutent pas la tâche du tout, ils attendent juste la fin de la tâche sur le thread courant et la bloquent jusqu'à la fin donc si nous voulons comparer, nous pouvons comparer Start et Wait à RunSynchronously:

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());
    }
}

Si vous essayez de commenter Démarrer ou RunSynchronously et exécutez le code, vous verrez que Start essaie et met la tâche en file d'attente sur le planificateur tandis que RunSynchronously va essayer de l'exécuter en ligne et en cas d'échec (retour faux), il le mettra simplement en file d'attente.

8
Stefano d'Antonio

Voyons d'abord ce code:

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

Dans cet exemple, nous avons essayé d'appeler RunSynchronously sur une tâche qui:

  • Renvoie une autre tâche avec le résultat (tâche de promesse)
  • Est une tâche "brûlante"
  • Une autre tâche prometteuse créée par async await
  • Tâche "froide" avec le délégué

Quels statuts auront-ils après la création?

  • En attente d'activation
  • WaitingToRun
  • En attente d'activation
  • Établi

Toutes les tâches "à chaud" sont créées avec le statut WaitingForActivationou WaitingToRun et sont associées à un planificateur de tâches.

La méthode RunSynchronously ne sait que travailler avec des tâches "froides" qui contiennent délégué et qui ont le statut Created.

Conclusion:

La méthode RunSynchronously était probablement apparue en l'absence de tâches "à chaud" ou n'avait pas été largement utilisée et avait été créée dans un but précis.

Nous pourrions vouloir l'utiliser au cas où nous aurions besoin d'une tâche "froide" avec un TaskScheduler personnalisé, sinon il n'est pas à jour et inutile.

Pour exécuter une tâche "chaude" de manière synchrone (ce que nous devrions éviter), nous pourrions utiliser task.GetAwaiter().GetResult(). En prime, il renverra l'exception d'origine et non une instance de AggregateException.

3
Fabjan