Autres conseils

En gros, les mots-clés async et await vous permettent de spécifier que l'exécution d'une méthode devrait arrêter à tous les usages de await, qui marquent les appels de méthodes asynchrones, puis reprendre une fois l'opération asynchrone est terminée. Cela vous permet d'appeler une méthode dans le thread principal et gérer le travail complexe d'une application de manière asynchrone, sans qu'il soit nécessaire de définir explicitement les discussions et se joint ou de bloquer le thread principal de l'application.

Pensez-y comme étant quelque peu semblable à une déclaration de yield return dans un procédé de production d'un IEnumerable. Lorsque le moteur d'exécution frappe le yield, il sera essentiellement sauvegarder l'état actuel de la méthode, et renvoyer la valeur ou de référence étant par céder. La prochaine fois que IEnumerator.MoveNext () est appelée sur l'objet de retour (qui est généré en interne par le moteur d'exécution), est restauré ancien état de la méthode de la pile et l'exécution se poursuit avec la ligne suivante après la yield return comme si nous avions jamais quitté la méthode. Sans ce mot-clé, un type IEnumerator doit être défini sur mesure à l'autre magasin et gérer les demandes d'itération, avec des méthodes qui peuvent devenir en effet très complexe.

De même, une méthode marquée comme async doit avoir au moins une await. Sur un await, le moteur d'exécution va enregistrer l'état de thread courant et la pile des appels, faire l'arrière appel asynchrone et dérouleur à la boucle de message de l'exécution pour gérer le message suivant et maintenir l'application réactive. Lorsque l'opération asynchrone est terminée, à la prochaine occasion de la planification, la pile d'appels à l'opération asynchrone est repoussé et a continué comme si l'appel était synchrone.

Alors, ces deux nouveaux mots clés simplifient essentiellement le codage des processus asynchrones, tout comme yield return simplifié la génération de enumerables personnalisés. Avec des mots-clés couple et un peu de connaissances de base, vous pouvez sauter tous les détails confus et souvent sujettes à l'erreur d'un modèle asynchrone traditionnel. Ce sera Précieuse en à peu près une application GUI évènementielle comme WinForms, WPF Silverlight.

La réponse actuellement acceptée est trompeur. await ne rien en pause. Tout d'abord, il peut être utilisé que dans les méthodes ou lambdas marqués comme async et retour Task ou void si vous ne vous souciez pas avoir instance Task en cours d'exécution dans cette méthode.

Voici une illustration:

internal class Program
{
    private static void Main(string[] args)
    {
        var task = DoWork();
        Console.WriteLine("Task status: " + task.Status);
        Console.WriteLine("Waiting for ENTER");
        Console.ReadLine();
    }

    private static async Task DoWork()
    {
        Console.WriteLine("Entered DoWork(). Sleeping 3");
        // imitating time consuming code
        // in a real-world app this should be inside task, 
        // so method returns fast
        Thread.Sleep(3000);

        await Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("async task iteration " + i);
                    // imitating time consuming code
                    Thread.Sleep(1000);
                }
            });

        Console.WriteLine("Exiting DoWork()");
    }
}

Sortie:

  

Entrée DoWork (). Sleeping 3
  async tâche itération 0
  Statut de la tâche: WaitingForActivation
  En attendant ENTRER
  async tâche itération 1
  async tâche itération 2
  async tâche itération 3
  async tâche itération 4
  async tâche itération 5
  async tâche itération 6
  async tâche itération 7
  async tâche itération 8
  async tâche itération 9
  Sortie DoWork ()

Pour toute personne nouvelle à la programmation asynchrone .NET, voici un (totalement faux) analogie dans un scénario, vous pouvez être plus familier avec - appels AJAX en utilisant JavaScript / JQuery. Une apparence de simple post jQuery AJAX comme ceci:

$.post(url, values, function(data) {
  // AJAX call completed, do something with returned data here
});

La raison pour laquelle nous traitons les résultats dans une fonction de rappel est si nous ne bloque pas le thread courant en attendant l'appel AJAX pour le retour. Seulement lorsque la réponse est prêt sera le get de rappel tiré, ce qui libère le thread courant pour faire d'autres choses dans le même temps.

Maintenant, si JavaScript pris en charge le mot-clé await (qui bien sûr, il n'a pas ( encore )), vous pouvez obtenir la même chose avec ceci:

var data = await $.post(url, values);
// AJAX call completed, do something with returned data here

C'est beaucoup plus propre, mais il est certain ressemble, nous avons introduit le code synchrone, le blocage. Mais le (faux) compilateur JavaScript aurait tout pris après await et branché sur un rappel, donc à l'exécution du second exemple se comporte comme le premier.

Il ne peut pas sembler comme il est vous permet d'économiser beaucoup de travail, mais quand il vient à des choses comme des contextes de gestion des exceptions et de synchronisation, le compilateur est en train de faire un beaucoup de soulever des objets lourds pour vous. Pour en savoir plus, je vous recommande le FAQ suivie série blog de Stephen Cleary .

Si je devais le mettre en œuvre en Java, il regarderait quelque chose comme ceci:

/**
 * @author Ilya Gazman
 */
public abstract class SynchronizedTask{

    private ArrayList<Runnable> listeners = new ArrayList<Runnable>();

    private static final ThreadPoolExecutor threadPoolExecutor =  new ThreadPoolExecutor(6, 6, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1000));

    public final void await(Runnable listener){
        synchronized (this) {
            listeners.add(listener);
        }
    }

    public void excecute(){
        onExcecute();
        for (int i = listeners.size() - 1; i >= 0; i--) {
            Runnable runnable;
            synchronized (this) {
                runnable = listeners.remove(i);
            }
            threadPoolExecutor.execute(runnable);
        }
    }

    protected abstract void onExcecute();
}

Votre application utiliserait comme ceci:

public class Test{
    private Job job = new Job();

    public Test() {
        craeteSomeJobToRunInBackground();
        methode1();
        methode2();
    }

    private void methode1(){
        System.out.println("Running methode 1");
        job.await(new Runnable() {

            @Override
            public void run() {
                System.out.println("Continue to running methode 1");
            }
        });
    }

    private void methode2(){
        System.out.println("Running methode 2");
    }

    private void craeteSomeJobToRunInBackground() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                job.excecute();
            }
        }).start();
    }

    private class Job extends SynchronizedTask{

        @Override
        protected void onExcecute() {
            try {
                Thread.sleep(1000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Job is done");
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top