Cómo llamar a un método de Visual C# de forma asincrónica

Resumen

El Microsoft.NET Framework facilita llamar a funciones de forma asincrónica. Llamar a funciones de forma asincrónica, el sistema que se ejecuten en segundo plano en un subproceso secundario mientras continúa la función de llamada a hacer otro trabajo. En una llamada de función (sincrónico) típica, la función se ejecuta inmediatamente en el mismo subproceso que hizo la llamada. La función de llamada espera a que se complete la llamada y recibe los resultados de la llamada antes de continuar. Por el contrario, cuando se realiza una llamada asincrónica, que recupere los resultados de la llamada asincrónica más adelante. En este artículo se muestra cómo hacerlo mediante Visual C#.

Requisitos


La lista siguiente describe el hardware recomendado, software, infraestructura de red y service packs que se necesitan:
  • Microsoft Windows 2000 o Microsoft Windows XP o Microsoft Windows Server 2003
  • Visual Studio .NET o Visual Studio 2005
En este artículo se supone que está familiarizado con los temas siguientes:
  • Llamar a métodos en Visual C#
  • Cómo utilizar delegados

Cómo realizar llamadas asincrónicas

Llamadas asincrónicas se realizan mediante delegados. Un delegado es un objeto que contiene una función. Los delegados proporcionan una función sincrónica y también proporcionan métodos para llamar a la función incluida de forma asincrónica. Estos métodos son BeginInvoke() y EndInvoke(). Las listas de parámetros de estos métodos varían dependiendo de la firma de la función que ajusta el delegado. Tenga en cuenta que la característica de IntelliSense de Visual Studio .NET no muestra BeginInvoke() y EndInvoke(), por lo que no se ve aparecen en las listas de función mientras escribe.


BeginInvoke() se utiliza para iniciar la llamada asincrónica. Tiene los mismos parámetros que la función incluida, más dos parámetros adicionales que se describen más adelante en este artículo. BeginInvoke() regresa inmediatamente y no espera a completar la llamada asincrónica. BeginInvoke() devuelve un objeto IAsyncResult .

La función EndInvoke() se utiliza para recuperar los resultados de la llamada asincrónica. Se puede llamar en cualquier momento después BeginInvoke(). Si la llamada asincrónica no ha finalizado todavía, EndInvoke() bloquea hasta que finalice. Los parámetros de la función EndInvoke() incluye el cabo y
parámetros ref que tiene la función incluida, más el objeto IAsyncResult devuelto por BeginInvoke().

El siguiente es un ejemplo de un delegado y sus métodos BeginInvoke() y EndInvoke() :
// The following delegate delegate string MethodDelegate(int iCallTime, out int iExecThread)  ;

// will have the following BeginInvoke() and EndInvoke methods:
IAsyncResult MethodDelegate.BeginInvoke(int iCallTime, out int iExecThread, AsyncCallback cb, object AsyncState);

string MethodDelegate.EndInvoke (out int iExecThread, IAsyncResult ar) ;

Hay cuatro maneras comunes de utilizar BeginInvoke() y EndInvoke() para realizar llamadas asincrónicas. Después de llamar a BeginInvoke(), puede:
  • Opcionalmente hacer algún otro trabajo y, a continuación, utilice EndInvoke().
  • Obtener un WaitHandle proporcionada por el objeto IAsyncResult , utilizar su método WaitOne para bloquear hasta que se señalice WaitHandle y, a continuación, llamar a EndInvoke().
  • Sondee el objeto IAsyncResult para determinar una vez finalizada la llamada asincrónica y, a continuación, llamar a EndInvoke().
  • Hacer que el sistema llame a una función de devolución de llamada especificado. Esta función de devolución de llamada llama a EndInvoke() y procesa los resultados de la llamada asincrónica cuando termine.
Ejemplos de código siguientes muestran estos patrones de llamar y contrastan con la realización de una llamada sincrónica mediante la siguiente función:
string LongRunningMethod (int iCallTime, out int iExecThread){
Thread.Sleep (iCallTime) ;
iExecThread = AppDomain.GetCurrentThreadId ();
return "MyCallTime was " + iCallTime.ToString() ;
}


LongRunningMethod() simula una función que se ejecuta durante mucho tiempo esperando en inactividad. Devuelve el tiempo de inactividad y el identificador del subproceso que se ejecuta. Si se llama de forma asincrónica, encontrará que el identificador de subproceso del subproceso en ejecución es diferente de la el subproceso de llamada.

El primer paso es definir el delegado que contiene la función:
delegate string MethodDelegate(int iCallTime, out int iExecThread)  ;

Ejemplo 1: Llamar a un método de forma sincrónica

Este ejemplo muestra cómo llamar a LongRunningMethod() sincrónicamente mediante un delegado MethodDelegate . Los demás ejemplos de contrastan esto haciendo llamadas de forma asincrónica.
  1. Inicie Microsoft Visual Studio .NET o Microsoft Visual Studio 2005.
  2. Cree un nuevo proyecto de aplicación de consola de Visual C# denominado AsyncDemo.
  3. Agregue una clase denominada AsyncDemo que se define como sigue para el proyecto en un nuevo archivo .cs:
    using System;using System.Threading ; 
    using System.Windows.Forms ;

    public class AsyncDemo
    {
    string LongRunningMethod (int iCallTime, out int iExecThread)
    {
    Thread.Sleep (iCallTime) ;
    iExecThread = AppDomain.GetCurrentThreadId ();
    return "MyCallTime was " + iCallTime.ToString() ;
    }

    delegate string MethodDelegate(int iCallTime, out int iExecThread) ;

    public void DemoSyncCall()
    {
    string s ;
    int iExecThread;

    // Create an instance of a delegate that wraps LongRunningMethod.
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;

    // Call LongRunningMethod using the delegate.
    s = dlgt(3000, out iExecThread);

    MessageBox.Show (string.Format ("The delegate call returned the string: \"{0}\",
    and the thread ID {1}", s, iExecThread.ToString() ) );
    }
    }

    Más adelante, esta clase muestra cómo realizar llamadas asincrónicas. Inicialmente, sin embargo, sólo contiene el método DemoSyncCall() , que muestra cómo llamar al delegado de forma sincrónica.
  4. Agregue el código siguiente en el cuerpo de la función Main que Visual Studio crea automáticamente en el proyecto:
    static void Main(string[] args){
    AsyncDemo ad = new AsyncDemo () ;
    ad.DemoSyncCall() ;
    }

  5. Presione CTRL+F5 para ejecutar la aplicación.

Ejemplo 2: Llamar a un método asincrónicamente utilizando el modelo de llamada EndInvoke()

En esta sección, el ejemplo invoca el mismo método de forma asincrónica. Es el patrón de llamada que se utiliza llamar a BeginInvoke, realizar algo de trabajo en el subproceso principal y, a continuación, llamar a EndInvoke(). Tenga en cuenta que EndInvoke() no vuelve hasta que haya finalizado la llamada asincrónica. Este patrón de llamada es útil cuando desea que el subproceso de llamada trabajar al mismo tiempo que se ejecuta la llamada asincrónica. Tener trabajo se producen al mismo tiempo, puede mejorar el rendimiento de muchas aplicaciones. Tareas comunes para que se ejecute asincrónicamente de esta forma son operaciones de archivos o red.
  1. Agregue un método denominado DemoEndInvoke() a la clase AsyncDemo . La función DemoEndInvoke muestra cómo llamar al delegado de forma asincrónica.
    public void DemoEndInvoke(){
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    string s ;
    int iExecThread;

    // Initiate the asynchronous call.
    IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);

    // Do some useful work here. This would be work you want to have
    // run at the same time as the asynchronous call.

    // Retrieve the results of the asynchronous call.
    s = dlgt.EndInvoke (out iExecThread, ar) ;

    MessageBox.Show (string.Format ("The delegate call returned the string: \"{0}\",
    and the number {1}", s, iExecThread.ToString() ) );
    }

  2. Edite el código fuente para el principal para que contenga el siguiente código:
    static void Main(string[] args){
    AsyncDemo ad = new AsyncDemo () ;
    ad.DemoEndInvoke() ;
    }

  3. Presione CTRL+F5 para ejecutar la aplicación.

Ejemplo 3: Llamar a un método asincrónicamente y utilizando WaitHandle para esperar la llamada para completar


En esta sección, el ejemplo llama al método de forma asincrónica y espera un WaitHandle antes de llamar a EndInvoke(). El IAsyncResult devuelto por BeginInvoke() tiene una propiedad AsyncWaitHandle . Esta propiedad devuelve un objeto WaitHandle que está señalado cuando finaliza la llamada asincrónica. Esperar en WaitHandle es una técnica de sincronización de subprocesos comunes. El subproceso de llamada espera el WaitHandle utilizando el método WaitOne() de WaitHandle. WaitOne() se bloquea hasta que se señalice WaitHandle . Cuando se devuelve WaitOne() , puede hacer un trabajo adicional antes de llamar a EndInvoke(). Como en el ejemplo anterior, esta técnica es útil para ejecutar operaciones de archivos o red que bloquean el subproceso de la llamada principal.
  1. Agregar una función denominada DemoWaitHandle() a la clase AsyncDemo . La función DemoWaitHandle() muestra cómo llamar al delegado de forma asincrónica.
    public void DemoWaitHandle (){
    string s ;
    int iExecThread;

    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;

    // Initiate the asynchronous call.
    IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);

    // Do some useful work here. This would be work you want to have
    // run at the same time as the asynchronous call.

    // Wait for the WaitHandle to become signaled.
    ar.AsyncWaitHandle.WaitOne() ;

    // Get the results of the asynchronous call.
    s = dlgt.EndInvoke (out iExecThread, ar) ;

    MessageBox.Show (string.Format ("The delegate call returned the string: \"{0}\",
    and the number {1}", s, iExecThread.ToString() ) );
    }

  2. Edite el código fuente para el principal para que contenga el siguiente código:
    static void Main(string[] args){
    AsyncDemo ad = new AsyncDemo () ;
    ad.DemoWaitHandle () ;
    }

  3. Presione CTRL+F5 para ejecutar la aplicación.

Ejemplo 4: Llamar a un método asincrónicamente utilizando el modelo de llamadas de sondeo

En esta sección, el ejemplo sondea el objeto IAsyncResult para averiguar una vez finalizada la llamada asincrónica. El objeto IAsyncResult devuelto por BeginInvoke() tiene una propiedad IsCompleted que devuelve True una vez finalizada la llamada asincrónica. A continuación, puede llamar a EndInvoke(). Este patrón de llamada es útil si la aplicación realiza trabajo continuo que no desea que se han bloqueado por una llamada a una función de larga duración. Una aplicación de Microsoft Windows es un ejemplo de esto. El subproceso principal de la aplicación de Windows puede continuar controlar la entrada del usuario mientras se ejecuta una llamada asincrónica. Periódicamente, puede comprobar IsCompleted para ver si se ha completado la llamada. Llama a EndInvoke IsCompleted devuelve True. Porque EndInvoke() se bloquea hasta que finaliza la operación asincrónica, la aplicación no llama a él hasta que sepa que la operación está terminada.
  1. Agregar una función denominada DemoPolling() a la clase AsyncDemo . La función DemoPolling() muestra cómo llamar al delegado de forma asincrónica y utilizar el sondeo para ver si el proceso está completo.
    public void DemoPolling(){
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    string s ;
    int iExecThread;

    // Initiate the asynchronous call.
    IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);

    // Poll IAsyncResult.IsCompleted
    while(ar.IsCompleted == false)
    {
    Thread.Sleep (10) ; // pretend to so some useful work
    }
    s = dlgt.EndInvoke (out iExecThread, ar) ;

    MessageBox.Show (string.Format ("The delegate call returned the string: \"{0}\",
    and the number {1}", s, iExecThread.ToString() ) );
    }


  2. Editar el código fuente principal. Reemplace el contenido de la función con el código siguiente:
    static void Main(string[] args){
    AsyncDemo ad = new AsyncDemo () ;
    ad.DemoPolling () ;
    }

  3. Presione CTRL+F5 para ejecutar la aplicación.

Ejemplo 5: Ejecutando una devolución de llamada cuando se completa un método asincrónico

En esta sección, el ejemplo proporciona un delegado de devolución de llamada a la función BeginInvoke() que el sistema se ejecuta cuando finaliza la llamada asincrónica. La devolución de llamada llama a EndInvoke() y procesa los resultados de la llamada asincrónica. Este patrón de llamada es útil si el subproceso que inicia la llamada asincrónica no necesita procesar los resultados de la llamada. El sistema invoca la devolución de llamada en un subproceso distinto del subproceso inicial cuando finaliza la llamada asincrónica.


Para utilizar este patrón de llamada, debe pasar a un delegado de tipo AsyncCallback como segundo al último parámetro de la función BeginInvoke() . BeginInvoke() también tiene un parámetro final de tipo objeto en el que se puede pasar cualquier objeto. Este objeto está disponible para la función de devolución de llamada cuando se invoca. Un uso importante de este parámetro es pasar el delegado que se utiliza para iniciar la llamada. La función de devolución de llamada, a continuación, puede utilizar la función EndInvoke() de ese delegado para completar la llamada. Este patrón de llamada se muestra a continuación.
  1. Agregue dos métodos denominados DemoCallback() y MyAsyncCallback() a la clase AsyncDemo . El método DemoCallback() muestra cómo llamar al delegado de forma asincrónica. Utiliza a un delegado para el método MyAsyncCallback() , que el sistema se llama cuando finaliza la operación asincrónica. MyAsyncCallback() llama a EndInvoke().
    public void DemoCallback(){
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    string s ;
    int iExecThread;

    // Create the callback delegate.
    AsyncCallback cb = new AsyncCallback(MyAsyncCallback);

    // Initiate the Asynchronous call passing in the callback delegate
    // and the delegate object used to initiate the call.
    IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, cb, dlgt);
    }

    public void MyAsyncCallback(IAsyncResult ar)
    {
    string s ;
    int iExecThread ;

    // Because you passed your original delegate in the asyncState parameter
    // of the Begin call, you can get it back here to complete the call.
    MethodDelegate dlgt = (MethodDelegate) ar.AsyncState;

    // Complete the call.
    s = dlgt.EndInvoke (out iExecThread, ar) ;

    MessageBox.Show (string.Format ("The delegate call returned the string: \"{0}\",
    and the number {1}", s, iExecThread.ToString() ) );
    }


  2. Editar el código fuente principal. Reemplace el contenido de la función con el código siguiente:
    static void Main(string[] args){
    AsyncDemo ad = new AsyncDemo () ;
    ad.DemoCallback() ;
    }

  3. Presione CTRL+F5 para ejecutar la aplicación.
Propiedades

Id. de artículo: 315582 - Última revisión: 22 ene. 2017 - Revisión: 1

Comentarios