30 votes

Quelle est la différence entre la programmation asynchrone et les threads ?

J'ai lu quelques async articles ici : http://www.asp.net/web-forms/tutorials/aspnet-45/using-asynchronous-methods-in-aspnet-45 et l'auteur dit :

Lorsque vous effectuez un travail asynchrone, vous n'utilisez pas toujours un thread. Par exemple, lorsque vous faites une demande de service web asynchrone, ASP.NET n'utilisera pas de threads entre l'appel de la méthode asynchrone et l'attente.

Donc ce que j'essaie de comprendre c'est, comment devient-il async si nous n'utilisons pas de Threads pour l'exécution simultanée ? Que signifie "on n'utilise pas toujours un thread" ?

Laissez-moi d'abord vous expliquer ce que je sais du travail avec les threads (un exemple rapide, bien sûr les threads peuvent être utilisés dans différentes situations autres que l'interface utilisateur et la méthodologie du travailleur ici)

  1. Vous avez le fil de l'interface utilisateur pour prendre les entrées et donner les sorties.
  2. Vous pouvez gérer les choses dans le Thread UI mais cela rend l'UI non réactive.
  3. Supposons que nous ayons une opération liée au flux et que nous devions télécharger des données.
  4. Et nous permettons également aux utilisateurs de faire d'autres choses pendant le téléchargement.
  5. Nous créons un nouveau fil de travail qui télécharge le fichier et modifie la barre de progression.
  6. Une fois que c'est fait, il n'y a plus rien à faire et le fil est tué.
  7. Nous reprenons le fil de l'UI.

Nous pouvons soit attendre le worker thread dans le UI thread en fonction de la situation, mais avant cela, pendant que le fichier est téléchargé, nous pouvons faire d'autres choses avec le UI thread et ensuite attendre le worker thread.

N'est-ce pas la même chose pour async la programmation ? Si non, quelle est la différence ? J'ai lu que async utilisations de la programmation ThreadPool pour en tirer des fils.

28voto

Stephen Cleary Points 91731

Les threads ne sont pas nécessaires pour la programmation asynchrone.

"Asynchrone" signifie que l'API ne bloque pas l'accès à l'utilisateur. en appelant fil. Il fait pas signifie qu'il y a un autre fil de discussion qui est blocage.

Tout d'abord, reprenez votre exemple d'interface utilisateur, en utilisant cette fois-ci des API asynchrones réelles :

  1. Vous avez le fil de l'interface utilisateur pour prendre les entrées et donner les sorties.
  2. Vous pouvez gérer les choses dans le Thread UI mais cela rend l'UI non réactive.
  3. Supposons que nous ayons une opération liée au flux et que nous devions télécharger des données.
  4. Et nous permettons également aux utilisateurs de faire d'autres choses pendant le téléchargement.
  5. Nous utilisons des API asynchrones pour télécharger le fichier. Aucun fil de travail n'est nécessaire.
  6. L'opération asynchrone signale sa progression au thread de l'interface utilisateur (qui met à jour la barre de progression), et elle signale également son achèvement au thread de l'interface utilisateur (qui peut y répondre comme tout autre événement).

Cela montre comment il peut n'y avoir qu'un seul thread impliqué (le thread de l'interface utilisateur), tout en ayant des opérations asynchrones en cours. Vous pouvez lancer plusieurs opérations asynchrones et pourtant n'avoir qu'un seul thread impliqué dans ces opérations - aucun thread n'est bloqué sur celles-ci.

async / await fournit une syntaxe très agréable pour lancer une opération asynchrone, puis la renvoyer, et faire en sorte que le reste de la méthode continue lorsque l'opération est terminée.

ASP.NET est similaire, sauf qu'il n'a pas de thread principal/UI. Au lieu de cela, il a un "contexte de demande" pour chaque demande incomplète. Les threads ASP.NET proviennent d'un pool de threads, et ils entrent dans le "contexte de requête" lorsqu'ils travaillent sur une requête ; lorsqu'ils ont terminé, ils quittent leur "contexte de requête" et retournent dans le pool de threads.

ASP.NET garde la trace des opérations asynchrones incomplètes pour chaque demande. Ainsi, lorsqu'un thread retourne au pool de threads, il vérifie s'il y a des opérations asynchrones en cours pour cette demande ; s'il n'y en a pas, la demande est terminée.

Donc, quand vous await une opération asynchrone incomplète dans ASP.NET, le thread incrémente ce compteur et revient. ASP.NET sait que la demande n'est pas complète parce que le compteur n'est pas à zéro, il ne termine donc pas la réponse. Le thread retourne dans le pool de threads et, à ce moment-là, il y a des éléments suivants pas de fils travaillant sur cette demande.

Lorsque l'opération asynchrone est terminée, elle planifie le reste de l'opération. async au contexte de la demande. ASP.NET saisit l'un de ses threads de traitement (qui peut être ou non le même thread que celui qui a exécuté la partie précédente de la méthode async ), le compteur est décrémenté, et le thread exécute la méthode async méthode.

ASP.NET vNext est légèrement différent ; il y a plus de support pour les gestionnaires asynchrones à travers le cadre. Mais le concept général est le même.

Pour plus d'informations :

6voto

ivenxu Points 245

La première fois que j'ai vu asynchrone et attendre Je pensais qu'il s'agissait du sucre syntaxique de C# pour le modèle de programmation asynchrone. Je me suis trompé, asynchrone et attendre sont plus que ça. Il s'agit d'un tout nouveau modèle asynchrone basé sur les tâches, http://www.microsoft.com/en-us/download/details.aspx?id=19957 est un bon article pour commencer. La plupart des classes FCL qui complètent TAP font appel à des méthodes APM (BegingXXX() et EndXXX()). Voici deux extraits de code pour TAP et AMP :

Echantillon de TAP :

    static void Main(string[] args)
    {
        GetResponse();
        Console.ReadLine();
    }

    private static async Task<WebResponse> GetResponse()
    {
        var webRequest = WebRequest.Create("http://www.google.com");
        Task<WebResponse> response = webRequest.GetResponseAsync();
        Console.WriteLine(new StreamReader(response.Result.GetResponseStream()).ReadToEnd());
        return response.Result;
    }

Exemple d'APM :

    static void Main(string[] args)
    {
        var webRequest = WebRequest.Create("http://www.google.com");
        webRequest.BeginGetResponse(EndResponse, webRequest);
        Console.ReadLine();
    }

    static void EndResponse(IAsyncResult result)
    {
        var webRequest = (WebRequest) result.AsyncState;
        var response = webRequest.EndGetResponse(result);
        Console.WriteLine(new StreamReader(response.GetResponseStream()).ReadToEnd());
    }

Finalement ces deux-là seront les mêmes, car GetResponseAsync() appelle BeginGetResponse() et EndGetResponse() à l'intérieur. Lorsque nous réfléchissons le code source de GetResponseAsync(), nous obtenons un code comme celui-ci :

task = Task<WebResponse>.Factory.FromAsync(
       new Func<AsyncCallback, object, IAsyncResult>(this.BeginGetResponse), 
       new Func<IAsyncResult, WebResponse>(this.EndGetResponse), null);

Pour APM, dans le BeginXXX(), il y a un argument pour une méthode de rappel qui sera invoquée lorsque la tâche (généralement une opération lourde d'E/S) sera terminée. La création d'un nouveau fil d'exécution et l'asynchronisme, les deux reviennent immédiatement dans le fil d'exécution principal, les deux sont débloqués. Du point de vue des performances, la création d'un nouveau thread coûtera plus de ressources lors du traitement des opérations liées aux E/S, telles que la lecture de fichiers, les opérations de base de données et la lecture du réseau. Il y a deux inconvénients à la création d'un nouveau thread,

  1. comme dans l'article que vous avez mentionné, il y a un coût de mémoire et CLR sont
    limitation du pool de threads.
  2. Le changement de contexte se produira. D'autre part, l'asynchrone ne créera aucun ne créera pas de thread manuellement et il n'y aura pas de changement de contexte lorsque les opérations liées aux entrées-sorties reviennent.

Voici une image qui peut aider à comprendre les différences :

enter image description here

Ce diagramme est tiré d'un article de MSDN " Pages asynchrones en ASP.NET 2.0 "qui explique en détail le fonctionnement de l'ancien système asynchrone dans ASP.NET 2.0.

Pour plus de détails sur le modèle de programmation asynchrone, veuillez consulter l'article de Jeffrey Richter intitulé " Mise en œuvre du modèle de programmation asynchrone du CLR ", il y a aussi plus de détails dans son livre "CLR via Csharp 3rd Edition" au chapitre 27.

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