60 votes

Les nouveaux mots clés "asynchrone" et "en attente" de C # 5.0 utilisent-ils plusieurs cœurs?

Deux nouveaux mots-clés ajoutés à la C# 5.0 langue sont async et await, les deux qui travaillent main dans la main pour exécuter une méthode C# en mode asynchrone, sans bloquer le thread appelant.

Ma question est, est-ce que ces méthodes réellement tirer parti des processeurs multi-cœurs et de l'exécuter en parallèle ou la méthode async exécuter dans le même thread noyau que l'appelant?

96voto

Eric Lippert Points 300275

Deux nouveaux mots-clés ajoutés à la C# 5.0 langue sont async et await, les deux qui travaillent main dans la main pour exécuter une méthode C# en mode asynchrone, sans bloquer le thread appelant.

Qui obtient dans le but de la fonctionnalité, mais il donne trop de "crédit" à la async/await fonctionnalité.

Permettez-moi d'être très, très clair sur ce point: await n'a pas la baguette magique pour provoquer une méthode synchrone à exécuter de manière asynchrone. Il ne permet pas de démarrer un nouveau thread pour exécuter la méthode sur le nouveau fil de discussion, par exemple. La méthode que vous appelez doit être la chose qui sait comment s'exécuter de manière asynchrone. La façon dont elle choisit de le faire est de ses affaires.

Ma question est, est-ce que ces méthodes réellement tirer parti des processeurs multi-cœurs et de l'exécuter en parallèle ou la méthode async exécuter dans le même thread noyau que l'appelant?

De nouveau, qui est entièrement à la méthode que vous appelez. Tout ce qui await fait est de demander au compilateur de réécrire la méthode dans un délégué, qui peut être adoptée qu'à la poursuite de la tâche asynchrone. Qui est, l' await FooAsync() signifie "appelez - FooAsync() et tout ce qui vient à l'arrière doit être quelque chose qui représente l'opération asynchrone qui vient de commencer. Dire que chose que lorsqu'il sait que l'opération asynchrone est terminée, il doit appeler ce délégué." Le délégué a la propriété que lorsqu'elle est invoquée, la méthode actuelle semble reprendre "où il l'a laissée".

Si la méthode que vous appelez les horaires de travail sur un autre thread possède une affinité avec un autre cœur, grand. Si elle commence une minuterie qui pings certains gestionnaire d'événement à l'avenir sur le thread de l'INTERFACE utilisateur, le grand. await ne se soucie pas. Il n'est de fait en sorte que quand le travail asynchrone est fait, le contrôle peut reprendre là où il l'avait laissé.

Une question que vous n'avez pas demandé, mais sans doute faudrait c'est:

Lorsque la tâche asynchrone est terminée et que le contrôle reprend là où il l'a laissée, est l'exécution dans le même thread comme il était avant?

Ça dépend du contexte. Dans une application winforms où vous attendent quelque chose de la thread de l'INTERFACE utilisateur, le contrôle ramasse à nouveau sur le thread de l'INTERFACE utilisateur. Dans une application console, peut-être pas.

67voto

Stephen Cleary Points 91731

Eric Lippert a une excellente réponse; je voulais juste décrire async parallélisme, un peu plus loin.

Le simple "série" est l'endroit où vous await juste une chose à la fois:

static void Process()
{
  Thread.Sleep(100); // Do CPU work.
}

static async Task Test()
{
  await Task.Run(Process);
  await Task.Run(Process);
}

Dans cet exemple, l' Test méthode de la file d'attente Process pour le pool de threads, et quand il se termine, il file Process nouveau pour le pool de threads. L' Test méthode complète après ~200ms. À tout moment, un seul thread est vraiment le déplacement du progrès de l'avant.

Une façon simple de paralléliser c'est d'utiliser Task.WhenAll:

static void Process()
{
  Thread.Sleep(100); // Do CPU work.
}

static async Task Test()
{
  // Start two background operations.
  Task task1 = Task.Run(Process);
  Task task2 = Task.Run(Process);

  // Wait for them both to complete.
  await Task.WhenAll(task1, task2);
}

Dans cet exemple, l' Test méthode de files d'attente Process du pool de threads, deux fois, puis il attend la fois pour compléter. L' Test méthode complète après ~100ms.

Task.WhenAll (et Task.WhenAny) ont été introduites avec async/await pour soutenir simple parallélisme. Cependant, la TPL est toujours là si vous avez besoin de quelque chose de plus avancé (vrai lié au PROCESSEUR de traitement en parallèle est un meilleur ajustement pour le TPL). TPL joue bien avec async/await.

J'ai de base en async parallélisme dans mon en async blog, ainsi que le "contexte" qu'Eric a fait allusion.

4voto

phoog Points 22667

Une méthode asynchrone retourne un awaitable objet (une GetAwaiter méthode), et le compilateur peut générer du code pour consommer cet objet, si vous appelez la méthode avec l' await mot-clé. Vous êtes également libre d'appeler une méthode de ce genre sans le mot clé await, et de consommer de l'objet de manière explicite.

L'objet encapsule une action asynchrone, ce qui peut ou peut ne pas fonctionner sur un autre thread. Eric Lippert l'article de l'Asynchronie de C# 5.0 quatrième partie: C'est pas de la magie considère comme un exemple de programmation asynchrone qui ne comporte qu'un seul thread.

2voto

Kendall Frey Points 19670

Etant donné que async et await sont basés sur le NPT, ils devraient fonctionner de manière très similaire. Par défaut, vous devez les traiter comme s’ils fonctionnaient sur un thread séparé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X