Comment et quand utiliser ‘async’ et ‘attendre’

D'après ce que j'ai compris, l'une des principales choses que async et await font est de rendre le code facile à écrire et à lire - mais les utilise-t-il égal à la fraie des fils de fond pour effectuer la logique de longue durée?

je suis en train d'essayer l'exemple le plus simple. J'ai ajouté quelques commentaires en ligne. Pouvez-vous préciser pour moi?

// I don't understand why this method must be marked as `async`.
private async void button1_Click(object sender, EventArgs e)
{
    Task<int> access = DoSomethingAsync();
    // task independent stuff here

    // this line is reached after the 5 seconds sleep from 
    // DoSomethingAsync() method. Shouldn't it be reached immediately? 
    int a = 1; 

    // from my understanding the waiting should be done here.
    int x = await access; 
}

async Task<int> DoSomethingAsync()
{
    // is this executed on a background thread?
    System.Threading.Thread.Sleep(5000);
    return 1;
}
764
demandé sur Roy 2013-01-22 13:29:58

20 réponses

en utilisant async et await le compilateur génère une machine d'état en arrière-plan.

voici un exemple sur lequel j'espère pouvoir expliquer certains des détails de haut niveau qui sont en cours:

public async Task MyMethodAsync()
{
    Task<int> longRunningTask = LongRunningOperationAsync();
    // independent work which doesn't need the result of LongRunningOperationAsync can be done here

    //and now we call await on the task 
    int result = await longRunningTask;
    //use the result 
    Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); // 1 second delay
    return 1;
}

OK, donc ce qui se passe ici:

  1. Task<int> longRunningTask = LongRunningOperationAsync(); commence l'exécution LongRunningOperation

  2. un travail indépendant est fait supposons que le Thread principal (Thread ID = 1) alors await longRunningTask est atteint.

    maintenant, si le longRunningTask n'est pas terminé et qu'il est toujours en cours d'exécution, MyMethodAsync() reviendra à sa méthode d'appel, ainsi le fil principal ne sera pas bloqué. Lorsque le longRunningTask est fait, alors un thread du ThreadPool (peut être n'importe quel thread) retournera à MyMethodAsync() dans son contexte précédent et poursuivra l'exécution (dans ce cas, en imprimant le résultat sur la console).

Un deuxième cas serait que la longRunningTask a déjà terminé son exécution et le résultat est disponible. En atteignant le await longRunningTask nous avons déjà le résultat donc le code va continuer à s'exécuter sur le même thread. (dans ce cas, imprimer le résultat sur la console). Bien sûr, ce n'est pas le cas pour l'exemple ci-dessus, où il y a un Task.Delay(1000) .

573
répondu Dan Dinu 2017-10-11 23:43:35

suite aux autres réponses, jetez un oeil à attendez (C# Référence)

et plus précisément à l'exemple inclus, il explique un peu votre situation

L'exemple de formulaires Windows suivant illustre l'utilisation d'attente dans un méthode asynchrone, WaitAsynchronouslyAsync. Contrastez le comportement de ce méthode avec le comportement de WaitSynchronously. Sans attendre opérateur appliqué à une tâche, WaitSynchronously runs synchronely malgré l'utilisation du modificateur async dans sa définition et un appel à Fil.Dormir dans son corps.

private async void button1_Click(object sender, EventArgs e)
{
    // Call the method that runs asynchronously.
    string result = await WaitAsynchronouslyAsync();

    // Call the method that runs synchronously.
    //string result = await WaitSynchronously ();

    // Display the result.
    textBox1.Text += result;
}

// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window 
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
    await Task.Delay(10000);
    return "Finished";
}

// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
    // Add a using directive for System.Threading.
    Thread.Sleep(10000);
    return "Finished";
}
133
répondu Adriaan Stander 2017-05-23 09:31:58

d'après ce que j'ai compris, l'une des principales choses que async et await font est de rendre le code facile à écrire et à lire.

ils vont rendre asynchrone code facile à écrire et à lire, Oui.

est-ce la même chose que de créer des fils de fond pour exécuter la logique de longue durée?

pas du tout.

//je ne comprends pas pourquoi cette méthode doit être marquée comme "asynchrone".

le mot-clé async active le mot-clé await . Ainsi, toute méthode utilisant await doit être marquée async .

/ / cette ligne est atteinte après le sommeil de 5 secondes de la méthode DoSomethingAsync (). Ne devrait-on pas l'atteindre immédiatement?

non, parce que async méthodes ne sont pas exécutées sur un autre thread par défaut.

//est-ce exécuté sur un thread d'arrière-plan?

Pas de.


vous pouvez trouver mon async / await intro utile. Les officiels MSDN sont également inhabituellement bons (en particulier la TAP section), et l'équipe async mis sur un excellent FAQ .

110
répondu Stephen Cleary 2014-06-13 12:49:02

explication

voici un exemple rapide d'async / wait à un niveau élevé. Il y a beaucoup plus de détails à considérer au-delà de cette.

Note: Task.Delay(1000) simule faire le travail pendant 1 seconde. Je pense qu'il est préférable de penser à cela comme à attendre une réponse d'une ressource externe. Comme notre code attend une réponse, le système peut définir la tâche en cours d'exécution sur le côté et revenir à elle une fois qu'elle est terminée. En attendant, il peut faire quelques d'autres travaux sur ce thread.

dans l'exemple ci-dessous, le premier bloc fait exactement cela. Il commence toutes les tâches immédiatement (les lignes Task.Delay ) et les met sur le côté. Le code s'arrêtera sur la ligne await a jusqu'à ce que le délai d'une seconde soit terminé avant de passer à la ligne suivante. Depuis b , c , d , et e tous ont commencé à exécuter presque au même moment que a (en raison de en l'absence de l'attente), ils devraient terminer à peu près au même moment dans ce cas.

dans l'exemple ci-dessous, le second bloc commence une tâche et attend qu'elle se termine (c'est ce que await fait) avant de commencer les tâches suivantes. Chaque itération de ceci prend 1 seconde. Le await est en pause et attend le résultat avant de continuer. C'est la principale différence entre les premier et deuxième blocs.

exemple

Console.WriteLine(DateTime.Now);

// This block takes 1 second to run because all
// 5 tasks are running simultaneously
{
    var a = Task.Delay(1000);
    var b = Task.Delay(1000);
    var c = Task.Delay(1000);
    var d = Task.Delay(1000);
    var e = Task.Delay(1000);

    await a;
    await b;
    await c;
    await d;
    await e;
}

Console.WriteLine(DateTime.Now);

// This block takes 5 seconds to run because each "await"
// pauses the program until the task finishes
{
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
}
Console.WriteLine(DateTime.Now);

sortie:

5/24/2017 2:22:50 PM
5/24/2017 2:22:51 PM (First block took 1 second)
5/24/2017 2:22:56 PM (Second block took 5 seconds)

informations supplémentaires concernant SynchronizationContext

Note: C'est ici que les choses deviennent un peu brumeuses pour moi, donc si je me trompe sur quelque chose, s'il vous plaît corriger moi et je vais mettre à jour la réponse. Il est important d'avoir une compréhension de base de la façon dont cela fonctionne, mais vous pouvez obtenir sans être un expert sur elle aussi longtemps que vous jamais utiliser ConfigureAwait(false) , bien que vous aurez probablement perdre une occasion pour l'optimisation, je suppose.

il y a un aspect de cela qui rend le concept async/attente un peu plus difficile à saisir. C'est le fait que dans cet exemple, tout se passe sur le même thread (ou du moins ce qui semble être le même thread en ce qui concerne son contexte de synchronisation). Par défaut, await restaurera le contexte de synchronisation du thread original qu'il était en cours d'exécution sur. Par exemple, dans ASP.NET vous avez un HttpContext qui est lié à un thread lorsqu'une requête entre en jeu. Ce contexte contient des choses spécifiques à la requête Http D'origine, comme l'objet Requête d'origine qui contient des choses comme la langue, l'adresse IP, les en-têtes, etc. Si vous changez les threads à mi-chemin du traitement de quelque chose, vous pourriez éventuellement finir par essayer de retirer des informations de cet objet sur un autre HttpContext qui pourrait être désastreux. Si vous savez que vous n'utiliserez pas contexte pour quoi que ce soit, vous pouvez choisir de "pas de soins". Cela permet essentiellement à votre code de s'exécuter sur un thread séparé sans apporter le contexte avec lui.

comment y parvenir? Par défaut ,le code await a; suppose que vous voulez capturer et restaurer le contexte:

await a; //Same as the line below
await a.ConfigureAwait(true);

si vous voulez permettre au code principal de continuer sur un nouveau thread sans le contexte d'origine, vous utilisez simplement false au lieu de true donc il sait qu'il n'a pas besoin de restaurer le contexte.

await a.ConfigureAwait(false);

après que le programme est fait en pause, il continuera potentiellement sur un fil entièrement différent avec un contexte différent. C'est de là que viendrait l'amélioration de la performance -- elle pourrait continuer sur n'importe quel thread disponible sans avoir à restaurer le contexte original avec lequel elle a commencé.

est-ce que ce truc est confus? Hell yeah! Pouvez-vous le comprendre? Probablement! Une fois que vous avez une compréhension des concepts, puis passer aux explications de Stephen Cleary qui ont tendance à être orientés davantage vers quelqu'un avec une compréhension technique de async/attendre déjà.

95
répondu Joe Phillips 2018-05-08 14:58:30

montrant les explications ci-dessus en action dans un simple programme de console -

class Program
{
    static void Main(string[] args)
    {
        TestAsyncAwaitMethods();
        Console.WriteLine("Press any key to exit...");
        Console.ReadLine();
    }

    public async static void TestAsyncAwaitMethods()
    {
        await LongRunningMethod();
    }

    public static async Task<int> LongRunningMethod()
    {
        Console.WriteLine("Starting Long Running method...");
        await Task.Delay(5000);
        Console.WriteLine("End Long Running method...");
        return 1;
    }
}

et la sortie est:

Starting Long Running method...
Press any key to exit...
End Long Running method...

ainsi,

  1. Principal démarre le long de la méthode en cours d'exécution via TestAsyncAwaitMethods. Qui revient immédiatement sans arrêter le fil courant et nous voyons immédiatement 'appuyez sur n'importe quelle touche pour sortir 'message
  2. pendant tout ce temps, la méthode Longrunnings'exécute dans le fond. Une fois terminé, un autre thread de Threadpool saisit ce contexte et affiche le message final

ainsi, pas de fil est bloqué.

45
répondu sppc42 2015-08-13 09:32:13

je pense que vous avez choisi un mauvais exemple avec System.Threading.Thread.Sleep

Point d'une tâche async est de la laisser exécuter en arrière-plan sans verrouiller le fil principal, comme faire un DownloadFileAsync

System.Threading.Thread.Sleep n'est pas quelque chose qui" se fait", il dort simplement, et donc votre ligne suivante est atteinte après 5 secondes ...

lire cet article, je pense que c'est une grande explication de async et await concept: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx

35
répondu Vnuk 2016-01-29 07:40:48

voici un programme de console rapide pour le rendre clair à ceux qui suivent. La méthode "TaskToDo" est votre méthode de longue durée que vous voulez faire async. Le faire fonctionner Async est fait par la méthode TestAsync. La méthode test loops exécute simplement les tâches" TaskToDo " et les exécute Async. Vous pouvez le voir dans les résultats parce qu'ils ne sont pas complets dans le même ordre d'exécution - ils se rapportent au thread de L'interface de configuration de la console lorsqu'ils sont complets. Simpliste, mais je pense que le simpliste les exemples mettent en évidence le cœur du modèle mieux que les exemples plus impliqués:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TestingAsync
{
    class Program
    {
        static void Main(string[] args)
        {
            TestLoops();
            Console.Read();
        }

        private static async void TestLoops()
        {
            for (int i = 0; i < 100; i++)
            {
                await TestAsync(i);
            }
        }

        private static Task TestAsync(int i)
        {
            return Task.Run(() => TaskToDo(i));
        }

        private async static void TaskToDo(int i)
        {
            await Task.Delay(10);
            Console.WriteLine(i);
        }
    }
}
17
répondu MarkWalls 2015-09-11 09:23:45

cette réponse vise à fournir certaines informations spécifiques ASP.NET.

en utilisant async / wait dans MVC controller, il est possible d'augmenter l'utilisation du pool de threads et d'obtenir un meilleur débit, comme expliqué dans l'article ci-dessous,

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

dans les applications web qui voit un grand nombre de demandes concurrentes au start-up ou a une charge élevée (où la concurrence augmente soudainement), le fait de rendre ces appels de service web asynchrones augmentera la la réactivité de votre application. Une requête asynchrone prend la même temps de traitement qu'une demande synchrone. Exemple, si une demande fait un appel de service web qui nécessite deux secondes pour complète, la demande prend deux secondes si elle est effectuée de manière synchrone ou asynchrone. Cependant, lors d'une appel asynchrone, un thread n'est pas bloqué pour répondre à d'autres requêtes alors qu'il attend que la première demande soit complétée. Par conséquent, asynchrone les requêtes empêchent la croissance de la file d'attente et du pool de threads lorsqu'il y a de nombreuses requêtes simultanées qu'invoquer des opérations de longue durée.

10
répondu Lex Li 2014-09-08 02:06:42

pour être honnête, je pense toujours que la meilleure explication est celle sur l'avenir et les promesses sur la Wikipédia: http://en.wikipedia.org/wiki/Futures_and_promises

l'idée de base est que vous avez un ensemble séparé de threads qui exécutent des tâches asynchrones. Lorsque vous l'utilisez. L'objet fait cependant la promesse qu'il exécutera l'opération à un moment donné et vous donnera le résultat lorsque vous le demanderez. Cela signifie qu'il bloquera quand vous demandez le résultat et n'a pas terminé, mais exécutez dans la piscine thread autrement.

de là, vous pouvez optimiser les choses: certaines opérations peuvent être mises en œuvre async et vous pouvez optimiser des choses comme le fichier IO et la communication réseau en regroupant les requêtes subséquentes et/ou en les réorganisant. Je ne suis pas sûr que ce soit déjà dans le cadre des tâches de Microsoft - mais si ce n'est pas le cas, ce serait l'une des premières choses que j'ajouterais.

vous pouvez en fait, mettre en œuvre le futur modèle TRI-of avec des rendements en C# 4.0. Si vous voulez savoir comment cela fonctionne exactement, je peux recommander ce lien qui fait un travail décent: http://code.google.com/p/fracture/source/browse/trunk/Squared/TaskLib/ . Cependant, si vous commencez à jouer avec vous-même, vous remarquerez que vous avez vraiment besoin de support de langage si vous voulez faire toutes les choses cool -- ce qui est exactement ce que Microsoft a fait.

9
répondu atlaste 2013-01-22 10:16:25

toutes les réponses ici utiliser la tâche.Delay() ou une autre fonction async intégrée. Mais voici mon exemple qui n'utilise aucune de ces fonctions async:

    // Starts counting to a large numbewr and then immediately displays message "i'm counting...". 
    // Then it waits for task to finish and displays "finished, press any key".
    static void asyncTest ()
    {
        Console.WriteLine("Started asyncTest()");
        Task<long> task = asyncTest_count();
        Console.WriteLine("Started counting, please wait...");
        task.Wait(); // if you comment this line you will see that message "Finished counting" will be displayed before we actually finished counting.
        //Console.WriteLine("Finished counting to " + task.Result.ToString()); // using task.Result seems to also call task.Wait().
        Console.WriteLine("Finished counting.");
        Console.WriteLine("Press any key to exit program.");
        Console.ReadLine();
    }

    static async Task<long> asyncTest_count()
    {
        long k = 0;
        Console.WriteLine("Started asyncTest_count()");
        await Task.Run(() =>
        {
            long countTo = 100000000;
            int prevPercentDone = -1;
            for (long i = 0; i <= countTo; i++)
            {
                int percentDone = (int)(100 * (i / (double)countTo));
                if (percentDone != prevPercentDone)
                {
                    prevPercentDone = percentDone;
                    Console.Write(percentDone.ToString() + "% ");
                }

                k = i;
            }
        });
        Console.WriteLine("");
        Console.WriteLine("Finished asyncTest_count()");
        return k;
    }
8
répondu Tone Škoda 2017-07-15 08:03:51

voir ce violon https://dotnetfiddle.net/VhZdLU (et l'améliorer si possible) pour exécuter un simple application console qui montre les usages de tâche, tâche.WaitAll (), async et attendent les opérateurs dans le même programme.

ce violon devrait clarifier votre concept de cycle d'exécution.

voici le code d'échantillon

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {               
        var a = MyMethodAsync(); //Task started for Execution and immediately goes to Line 19 of the code. Cursor will come back as soon as await operator is met       
        Console.WriteLine("Cursor Moved to Next Line Without Waiting for MyMethodAsync() completion");
        Console.WriteLine("Now Waiting for Task to be Finished");       
        Task.WaitAll(a); //Now Waiting      
        Console.WriteLine("Exiting CommandLine");       
    }

    public static async Task MyMethodAsync()
    {
        Task<int> longRunningTask = LongRunningOperation();
        // independent work which doesn't need the result of LongRunningOperationAsync can be done here
        Console.WriteLine("Independent Works of now executes in MyMethodAsync()");
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine("Result of LongRunningOperation() is " + result);
    }

    public static async Task<int> LongRunningOperation() // assume we return an int from this long running operation 
    {
        Console.WriteLine("LongRunningOperation() Started");
        await Task.Delay(2000); // 2 second delay
        Console.WriteLine("LongRunningOperation() Finished after 2 Seconds");
        return 1;
    }   

}

Trace provenant de la fenêtre de sortie: enter image description here

6
répondu vibs2006 2018-01-24 12:45:39
public static void Main(string[] args)
{
    string result = DownloadContentAsync().Result;
    Console.ReadKey();
}

// You use the async keyword to mark a method for asynchronous operations.
// The "async" modifier simply starts synchronously the current thread. 
// What it does is enable the method to be split into multiple pieces.
// The boundaries of these pieces are marked with the await keyword.
public static async Task<string> DownloadContentAsync()// By convention, the method name ends with "Async
{
    using (HttpClient client = new HttpClient())
    {
        // When you use the await keyword, the compiler generates the code that checks if the asynchronous operation is finished.
        // If it is already finished, the method continues to run synchronously.
        // If not completed, the state machine will connect a continuation method that must be executed WHEN the Task is completed.


        // Http request example. 
        // (In this example I can set the milliseconds after "sleep=")
        String result = await client.GetStringAsync("http://httpstat.us/200?sleep=1000");

        Console.WriteLine(result);

        // After completing the result response, the state machine will continue to synchronously execute the other processes.


        return result;
    }
}
3
répondu Weslley Rufino de Lima 2018-02-22 15:49:47

si je comprends bien, il y a aussi un troisième terme à ajouter au mélange: Task .

Async est juste un qualificatif que vous mettez sur votre méthode pour dire que c'est une méthode asynchrone.

Task est le retour de la fonction async . Il s'exécute de façon asynchrone.

vous await une tâche. Quand l'exécution de code atteint cette ligne, le contrôle saute de nouveau à l'appelant de votre original environnant fonction.

si au lieu de cela, vous assignez le retour d'une fonction async (c'est-à-dire Task ) à une variable, lorsque l'exécution du code atteint cette ligne, il suffit continue au-delà de cette ligne dans la fonction environnante tandis que le Task s'exécute asynchrone.

2
répondu user21306 2017-06-02 21:15:25

Pour le plus rapide d'apprentissage..

  • comprendre le flux d'exécution de la méthode(avec un diagramme): 3 minutes

  • introspection de questions( pour apprendre): 1 min

  • passer rapidement à travers le sucre de syntaxe: 5 minutes

  • partager la confusion d'un développeur: 5 minutes

  • problème: changer rapidement une mise en œuvre réelle du code normal pour Code Async: 2 minutes

  • où aller?

comprendre le flux d'exécution de la méthode(avec un diagramme): 3 minutes

dans cette image, il suffit de se concentrer sur #6 enter image description here

au #6 step: AccessTheWebAsync () est à court de travail, ce qu'il peut faire sans résultat de getStringTask. Par conséquent, AccessTheWebAsync utilise un opérateur d'attente pour suspendre sa progression et redonner le contrôle(rendement) à l'appelant. AccessTheWebAsync renvoie une tâche(de valeur de retour de chaîne) à l'appelant. La tâche représente une promesse de produire une chaîne de résultat. mais quand rappellera-t-il? encore un 2e appel?

l'appelant D'Accessthebasync () a rien que d'attendre (il aurait pu faire quelques tâches internes et attendre ensuite si nécessaire). Ainsi, l'appelant attend L'accès au réseau Webasync, et L'accès au réseau webasync attend GetStringAsync en ce moment.

rappelez-vous, la méthode était déjà retournée, elle ne peut plus revenir(pas de seconde fois). Alors comment savoir à la cliente? Il s'agit de tâches! La tâche a été retournée. tâche attendue (pas de méthode, pas de valeur). La valeur sera définie dans Tâche. Le statut de la tâche sera de remplir. L'appelant ne surveille que la tâche. Plus loin se lit pour plus tard ici .

introspection des questions pour apprendre: 1 min

ajustons un peu la question:

comment et quand utiliser async et await Tasks ?

parce que l'apprentissage Task couvre automatiquement les 2 autres. Pour l'amour de l'apprentissage tout au moins. Bien sûr, Ceci est une réponse à votre question sur async et await .

passer rapidement à travers le sucre de syntaxe: 5 minutes

  • avant conversion

    internal static int Method(int arg0, int arg1) { int result = arg0 + arg1; IO(); // Do some long running IO. return result; }

  • une Autre Tâche-identifiés méthode à appeler ci-dessus méthode

    internal static Task<int> MethodTask(int arg0, int arg1) { Task<int> task = new Task<int>(() => Method(arg0, arg1)); task.Start(); // Hot task (started task) should always be returned. return task; }

avons-nous mentionné attente ou async? Aucun. Appelez la méthode ci-dessus et vous obtenez une tâche. De laquelle vous pouvez contrôler. Vous savez déjà ce que rapporte la tâche.. entier.

  • appeler une tâche est un peu délicat. Appelons MethodTask ()

    internal static async Task<int> MethodAsync(int arg0, int arg1) { int result = await HelperMethods.MethodTask(arg0, arg1); return result; }

d'être terminé. D'où le await . Puisque nous utilisons l'attente, nous devons utiliser async(obligatoire) et MethodAsync avec 'Async' comme préfixe (standard de codage). Se lit en outre pour plus tard ici

partager la confusion d'un développeur: 5 minutes

un développeur a fait une erreur de ne pas implémenter Task mais cela fonctionne toujours! Essayez de comprendre la question et juste la réponse acceptée fourni ici . J'espère que vous avez lu et entièrement compris. De même, dans notre exemple, appeler un déjà construit MethodAsync() est beaucoup plus facile que de mettre en œuvre cette méthode avec un Task ( MethodTask() ) nous-mêmes. La plupart des développeurs trouvent difficile d'obtenir leur tête autour de Tasks tout en convertissant un code en asynchrone.

conseil: essayez de trouver une implémentation Async existante (comme MethodAsync ou ToListAsync ) pour externaliser la difficulté. Nous avons donc seulement besoin de traiter avec Async et await (ce qui est facile et assez similaire à la normale code)

problème: changer rapidement une mise en œuvre réelle du code normal à Opération Async: 2 minutes

La ligne de Code

affichée ci-dessous dans la couche de données a commencé à se briser(à de nombreux endroits). Parce que nous avons mis à jour une partie de notre code de .net framework 4.2 à .Net core. On a dû régler ça en une heure dans toute l'application!

var myContract = query.Where(c => c.ContractID == _contractID).First();

easypeasy!

  1. Entitefram Framework nuget (it has Queryable extensions)
  2. namespace = Microsoft.Entiteframeworkcore

le code a été changé comme ceci

var myContract = await query.Where(c => c.ContractID == _contractID).FirstAsync();
  1. méthode signature changée de

    Contract GetContract(int contractnumber)

    à

    async Task<Contract> GetContractAsync(int contractnumber)

  2. méthode d'appel a également touché: GetContractAsync(123456); a été appelé comme GetContractAsync(123456).Result;

  3. nous l'avons changé partout en 30 minutes!

mais l'architecte nous a dit de ne pas utiliser la bibliothèque Entitefram Framework juste pour cela! oops! le drame! Puis nous avons fait une implémentation de tâche personnalisée. Qui vous savez comment. Toujours facile!

Où allons-nous? Il y a une vidéo rapide merveilleuse que nous pourrions regarder sur convertissant les appels synchrones en asynchrones en ASP.Net Core , parce que c'est probablement la direction que l'on prendrait après avoir lu ceci.

2
répondu Blue Clouds 2018-09-21 05:09:07

est de les utiliser égal à frayer fils de fond pour effectuer de longues la durée de la logique?

Cet article MDSN:Programmation Asynchrone avec async et await (C#) , explique explicitement:

les mots-clés async et en attente ne causent pas de threads supplémentaires à être créé. Les méthodes Async ne nécessitent pas de lecture multiple car un async la méthode ne fonctionne pas sur son propre thread. Le méthode fonctionne sur le courant contexte de synchronisation et l'utilise de temps sur le fil lors de la la méthode est active.

1
répondu Dmitry G. 2016-10-04 16:16:30

dans le code suivant, la méthode HttpClient GetByteArrayAsync renvoie une tâche, getContentsTask. La tâche est une promesse pour produire la réelle tableau d'octets lorsque la tâche est terminée. L'opérateur d'attente est appliqué à getContentsTask pour suspendre l'exécution dans SumPageSizesAsync jusqu'à ce que getContentsTask soit terminé. En attendant, le contrôle est retourné à l'appelant de SumPageSizesAsync. Lorsque getContentsTask est terminé, l'expression d'attente est évaluée à un tableau d'octets.

private async Task SumPageSizesAsync()
{
    // To use the HttpClient type in desktop apps, you must include a using directive and add a 
    // reference for the System.Net.Http namespace.
    HttpClient client = new HttpClient();
    // . . .
    Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
    byte[] urlContents = await getContentsTask;

    // Equivalently, now that you see how it works, you can write the same thing in a single line.
    //byte[] urlContents = await client.GetByteArrayAsync(url);
    // . . .
}
1
répondu lazydeveloper 2017-08-31 18:40:12

à un niveau supérieur:

1) le mot-clé Async active l'attente et c'est tout ce qu'il fait. Le mot-clé Async n'exécute pas la méthode dans un thread séparé. La méthode asynchrone de départ fonctionne de manière synchrone jusqu'à ce qu'elle atteigne attend sur une tâche longue.

2) Vous pouvez attendre sur une méthode qui renvoie une tâche ou une tâche de type T. Vous ne pouvez pas attendre sur la méthode async void.

3) le moment de la rencontre du fil principal attend sur la tâche fastidieuse ou quand le travail est commencé, le thread principal renvoie à l'appelant de la méthode actuelle.

4) si le thread principal voit en attente sur une tâche qui est encore en cours d'exécution, il ne l'attend pas et retourne à l'appelant de la méthode courante. De cette façon, la demande demeure réceptive.

5) attend sur la tâche de traitement, va maintenant exécuter sur un thread séparé du pool de thread.

6) lorsque cette tâche d'attente est terminée, tous le code ci-dessous sera exécuté par le thread séparé

ci-dessous est le code de l'échantillon. L'exécuter et vérifier le thread id

using System;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncAwaitDemo
{
    class Program
    {
        public static async void AsynchronousOperation()
        {
            Console.WriteLine("Inside AsynchronousOperation Before AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            //Task<int> _task = AsyncMethod();
            int count = await AsyncMethod();

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod Before Await, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            //int count = await _task;

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await Before DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            DependentMethod(count);

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await After DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
        }

        public static async Task<int> AsyncMethod()
        {
            Console.WriteLine("Inside AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            int count = 0;

            await Task.Run(() =>
            {
                Console.WriteLine("Executing a long running task which takes 10 seconds to complete, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(20000);
                count = 10;
            });

            Console.WriteLine("Completed AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            return count;
        }       

        public static void DependentMethod(int count)
        {
            Console.WriteLine("Inside DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId + ". Total count is " + count);
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Started Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            AsynchronousOperation();

            Console.WriteLine("Completed Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            Console.ReadKey();
        }

    }
}
1
répondu ABajpai 2018-08-05 17:38:51

les réponses ici sont utiles comme une orientation générale sur l'attente/async. Ils contiennent également quelques détails sur la façon dont wait/async est câblé. Je voudrais partager avec vous quelques expériences pratiques que vous devriez savoir avant d'utiliser ce modèle de conception.

le terme" attendre " est littéral, donc quel que soit le fil sur lequel vous l'appelez, il attendra le résultat de la méthode avant de continuer. Sur le filetage premier plan , il s'agit d'un filetage 151970920" catastrophe . Le fil au premier plan porte le fardeau de construire votre application, y compris les vues, Les modèles de vue, les animations initiales, et tout ce que vous avez boot-strapped avec ces éléments. Ainsi, lorsque vous attendez le fil avant-plan, vous stop l'application. L'utilisateur attend et attend quand rien ne semble se produire. Cela fournit une expérience utilisateur négatif.

vous pouvez certainement attendre un fil de fond en utilisant divers moyens:

Device.BeginInvokeOnMainThread(async () => { await AnyAwaitableMethod(); });

// Notice that we do not await the following call, 
// as that would tie it to the foreground thread.
try
{
Task.Run(async () => { await AnyAwaitableMethod(); });
}
catch
{}

le code complet pour ces remarques est https://github.com/marcusts/xamarin-forms-annoyances . Voir la solution appelée AwaitAsyncAntipattern.la sln.

le site GitHub fournit également des liens vers une discussion plus détaillée sur ce sujet.

0
répondu Stephen Marcus 2018-04-13 22:47:14

ci-dessous est le code qui lit le fichier excel en ouvrant la boîte de dialogue et puis utilise async et attendre pour exécuter asynchrone le code qui lit une par une ligne d'excel et se lie à la grille

    namespace EmailBillingRates
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        lblProcessing.Text = "";
    }

    private async void btnReadExcel_Click(object sender, EventArgs e)
    {
        string filename = OpenFileDialog();

        Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
        Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename);
        Microsoft.Office.Interop.Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
        Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange;
        try
        {
            Task<int> longRunningTask = BindGrid(xlRange);
            int result = await longRunningTask;

        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message.ToString());
        }
        finally
        {
            //cleanup  
           // GC.Collect();
            //GC.WaitForPendingFinalizers();

            //rule of thumb for releasing com objects:  
            //  never use two dots, all COM objects must be referenced and released individually  
            //  ex: [somthing].[something].[something] is bad  

            //release com objects to fully kill excel process from running in the background  
            Marshal.ReleaseComObject(xlRange);
            Marshal.ReleaseComObject(xlWorksheet);

            //close and release  
            xlWorkbook.Close();
            Marshal.ReleaseComObject(xlWorkbook);

            //quit and release  
            xlApp.Quit();
            Marshal.ReleaseComObject(xlApp);
        }

    }

    private void btnSendEmail_Click(object sender, EventArgs e)
    {

    }

    private string OpenFileDialog()
    {
        string filename = "";
        OpenFileDialog fdlg = new OpenFileDialog();
        fdlg.Title = "Excel File Dialog";
        fdlg.InitialDirectory = @"c:\";
        fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*";
        fdlg.FilterIndex = 2;
        fdlg.RestoreDirectory = true;
        if (fdlg.ShowDialog() == DialogResult.OK)
        {
            filename = fdlg.FileName;
        }
        return filename;
    }

    private async Task<int> BindGrid(Microsoft.Office.Interop.Excel.Range xlRange)
    {
        lblProcessing.Text = "Processing File.. Please wait";
        int rowCount = xlRange.Rows.Count;
        int colCount = xlRange.Columns.Count;

        // dt.Column = colCount;  
        dataGridView1.ColumnCount = colCount;
        dataGridView1.RowCount = rowCount;

        for (int i = 1; i <= rowCount; i++)
        {
            for (int j = 1; j <= colCount; j++)
            {
                //write the value to the Grid  
                if (xlRange.Cells[i, j] != null && xlRange.Cells[i, j].Value2 != null)
                {
                     await Task.Delay(1);
                     dataGridView1.Rows[i - 1].Cells[j - 1].Value =  xlRange.Cells[i, j].Value2.ToString();
                }

            }
        }
        lblProcessing.Text = "";
        return 0;
    }
}

internal class async
{
}

}

0
répondu Zaheer Abbas 2018-04-26 10:51:54

Async / Attente

Accally Async / wait sont une paire de mots clés qui sont juste du sucre syntaxique pour créer un rappel d'une tâche asynchrone.

prendre par exemple cette opération:

    public static void DoSomeWork()
    {
        var task = Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS NOT bubbling up due to the different threads
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // This is the callback
        task.ContinueWith((t) => {
            // -> Exception is swallowed silently
            Console.WriteLine("Completed");

            // [RUNS ON WORKER THREAD]
        });
    }

cette méthode présente des inconvénients Servaux. Les erreurs ne sont pas transmis et c'est extrêmement difficile à lire. Mais Async et attente sont venus nous aider:

    public async static void DoSomeWork()
    {
        var result = await Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS bubbling up
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // every thing below is a callback 
        // (including the calling methods)

        Console.WriteLine("Completed");

    }

les appels D'attente doivent être en Async méthode. Cela présente certains avantages:

  • retourne le résultat
  • crée automatiquement un callback
  • vérifie les erreurs et les laisse apparaître dans callstack (seulement jusqu'à aucun-attendez les appels dans callstack)
  • attend le résultat
  • libère le fil principal
  • exécute le rappel sur le fil principal
  • utilise un fil ouvrier à partir du pool de threads pour la tâche
  • rend le code facile à lire
  • et beaucoup plus

NOTE : Async et attente sont utilisés avec appels asynchrones et non pour les faire. Vous devez utiliser tâche Libary pour cela, comme tâche.Exécuter. )(

voici une comparaison entre l'attente et aucune attente solutions

C'est le néant async solution:

    public static long DoTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]
        var task = Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        Thread.Sleep(1000);
        // goes directly further
        // WITHOUT waiting until the task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 50 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

C'est la méthode async:

    public async static Task<long> DoAwaitTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]

        await Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        // Waits until task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 2050 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

vous pouvez appeler une méthode asynchrone sans le mot-clé attente mais cela signifie que toute Exception ici sont avalés en mode de libération:

    public static Stopwatch stopWatch { get; } = new Stopwatch();

    static void Main(string[] args)
    {
        Console.WriteLine("DoAwaitTask: " + DoAwaitTask().Result + " ms");
        // 2050 (2000 more because of the await)
        Console.WriteLine("DoTask: " + DoTask() + " ms");
        // 50
        Console.ReadKey();
    }

Async et attente ne sont pas destinés au calcul parallèle. Ils sont utilisés pour ne pas bloquer votre fil principal. Si c'est à propos asp.net ou des fenêtres applicantions. Bloquer votre thread principal en raison d'un appel réseau est une mauvaise chose. Si vous faites cela votre application va devenir insensible ou pourrait se planter.

Check out ms docs pour obtenir des exemples.

Espérons que cette aide;

0
répondu Hakim 2018-09-27 17:45:43