Pregunta

Puede alguien explicar lo que hace la función de await?

¿Fue útil?

Solución

hablado de esto en el PDC ayer!

Await se utiliza conjuntamente con las tareas (programación paralelo) en .NET. Es un ser palabra clave introducida en la próxima versión de .NET. Es más o menos le permite "pausar" la ejecución de un método para esperar a que la tarea para la ejecución completa. He aquí una breve ejemplo:

//create and run a new task  
Task<DataTable> dataTask = new Task<DataTable>(SomeCrazyDatabaseOperation);

//run some other code immediately after this task is started and running  
ShowLoaderControl();  
StartStoryboard();

//this will actually "pause" the code execution until the task completes.  It doesn't lock the thread, but rather waits for the result, similar to an async callback  
// please so also note, that the task needs to be started before it can be awaited. Otherwise it will never return
dataTask.Start();
DataTable table = await dataTask;

//Now we can perform operations on the Task result, as if we're executing code after the async operation completed  
listBoxControl.DataContext = table;  
StopStoryboard();  
HideLoaderControl();

Otros consejos

Básicamente, las palabras clave y async await permiten especificar que la ejecución de un método debe parar en todos los usos de await, que marcan las llamadas a métodos asíncronos, y luego reanudará una vez que la operación asincrónica es completa. Esto le permite llamar a un método en el hilo principal de una aplicación y manejar trabajos complejos de forma asíncrona, sin la necesidad de definir explícitamente los hilos y se une o bloquear el hilo principal de la aplicación.

Piense en ello como algo similar a una declaración yield return en un método de producción de un IEnumerable. Cuando el tiempo de ejecución golpea el yield, será básicamente guardar el estado actual del método, y devolver el valor o referencia que se produjeron. La próxima vez IEnumerator.MoveNext () se llama en el objeto de retorno (que se genera internamente por el tiempo de ejecución), viejo estado del método se restaura a la pila y la ejecución continúa con la siguiente línea después de la yield return como si nunca nos habíamos dejado el método. Sin esta palabra clave, un tipo de IEnumerator debe ser definida de forma personalizada a estado almacenar y manejar las solicitudes de iteración, con métodos que pueden llegar a ser muy compleja de hecho.

Del mismo modo, un método marcado como async debe tener al menos un await. En una await, el tiempo de ejecución salvará estado de pila y la llamada del hilo actual, realizar la llamada asincrónica, y volver a desenrollar el bucle de mensajes del tiempo de ejecución para manejar la siguiente mensaje y mantener la aplicación sensible. Cuando la operación asincrónica es completa, en la siguiente oportunidad de programación, la pila de llamadas a la operación asincrónica es empujado de nuevo y continuó como si la llamada fue sincrónica.

Por lo tanto, estas dos nuevas palabras clave básicamente simplificar la codificación de los procesos asíncronos, al igual que yield return simplifica la generación de enumerables personalizados. Con un par de palabras clave y un poco de conocimiento de fondo, puede saltarse todos los confusos ya menudo propensos a errores detalles de un modelo asíncrono tradicional. Esto será de gran valor en casi cualquier aplicación GUI basada en eventos como WinForms, WPF de Silverlight.

La respuesta aceptada actualmente es engañoso. await no está en pausa cualquier cosa. En primer lugar, sólo se puede utilizar en los métodos o lambdas marcados como async y volviendo Task o void si no le importa tener Task ejemplo se ejecuta en este método.

He aquí una ilustración:

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

Salida:

  

DoWork introducido (). Dormir 3
  tarea asíncrona iteración 0
  Estado de la tarea: WaitingForActivation
  A la espera de ENTER
  tarea asíncrona iteración 1 |   tarea asíncrona iteración 2
  tarea asíncrona iteración 3
  tarea asíncrona iteración 4
  tarea asíncrona iteración 5
  tarea asíncrona iteración 6
  tarea asíncrona iteración 7
  tarea asíncrona iteración 8
  tarea asíncrona iteración 9
  Al salir DoWork ()

Para cualquier persona nueva a la programación asincrónica en .NET, he aquí una (falsa totalmente) analogía en un escenario que puede ser más familiarizados con - llamadas AJAX utilizando JavaScript / jQuery. Un simple jQuery AJAX correos es similar al siguiente:

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

La razón de procesar los resultados en una función de devolución de llamada es para que no bloqueen el flujo actual a la espera de la llamada AJAX para el retorno. Sólo cuando la respuesta está lista será la devolución de llamada get disparado, liberando el hilo actual para hacer otras cosas en la media hora.

Ahora, si JavaScript apoyó la palabra clave await (que por supuesto no lo hace ( todavía )), se podría lograr el mismo con esto:!

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

Eso es mucho más limpio, pero parece seguro que introdujo como síncrona, el bloqueo de código. Pero la (falsa) de JavaScript compilador habría tomado todo lo que después await y por cable en una devolución de llamada, por lo que en tiempo de ejecución el segundo ejemplo se comportaría igual que la primera.

Puede que no parezca que se está ahorrando mucho trabajo, pero cuando se trata de cosas como el manejo de excepciones y sincronización contextos, el compilador está haciendo realmente un mucho de trabajo pesado para usted. Para más información, os recomiendo el Preguntas frecuentes seguido por el blog de la serie Stephen Cleary .

Si tuviera que ponerlo en práctica en Java que se vería algo como esto:

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

Su aplicación podría utilizar de esta manera:

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");
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top