Evaluar y enviar comentarios
Esta página es específica de
Microsoft Visual Studio 2005/.NET Framework 2.0

Hay además otras versiones disponibles para:
Manual del programador de .NET Framework
Llamar a métodos sincrónicos de forma asincrónica

.NET Framework permite llamar a cualquier método de forma asincrónica. Para ello, defina un delegado con la misma firma que el método al que desee llamar; Common Language Runtime define automáticamente los métodos BeginInvoke y EndInvoke para este delegado, con las firmas adecuadas.

El método BeginInvoke inicia la llamada asincrónica. Tiene los mismos parámetros que el método que quiere ejecutar de forma asincrónica, más dos parámetros opcionales adicionales. El primer parámetro es un delegado AsyncCallback que hace referencia a un método que se habrá de llamar cuando finalice la llamada asincrónica. El segundo parámetro es un objeto definido por el usuario que pasa información al método de devolución de llamada. BeginInvoke regresa inmediatamente y no espera a que se complete la llamada asincrónica. BeginInvoke devuelve un objeto IAsyncResult, que puede utilizarse para supervisar el progreso de la llamada asincrónica.

El método EndInvoke recupera los resultados de la llamada asincrónica. Se puede llamar a este método en cualquier momento, siempre y cuando se haya llamado antes al método BeginInvoke; si la llamada asincrónica no ha terminado, el método EndInvoke bloqueará el subproceso de llamada hasta que finalice dicha llamada. Entre los parámetros de EndInvoke se incluyen los parámetros out y ref (<Out> ByRef y ByRef en Visual Basic) del método que desea ejecutar asincrónicamente, además del resultado IAsyncResult devuelto por BeginInvoke.

NoteNota

La característica IntelliSense en Visual Studio 2005 muestra los parámetros de BeginInvoke y EndInvoke. Si no está utilizando Visual Studio u otra herramienta similar, o si está utilizando C# con Visual Studio 2005, consulte Información general sobre la programación asincrónica, donde encontrará una descripción de los parámetros definidos para estos métodos.

En los ejemplos de código de este tema se muestran cuatro de las formas más comunes de utilizar los métodos BeginInvoke y EndInvoke para realizar llamadas asincrónicas. Después de llamar al método BeginInvoke, puede hacer lo siguiente:

  • Realizar algo de trabajo y, después, llamar al método EndInvoke para que se bloquee hasta que termine la llamada.

  • Obtener un objeto WaitHandle mediante la propiedad System.IAsyncResult.AsyncWaitHandle, utilizar su método WaitOne para bloquear la ejecución hasta que se señale WaitHandle y, a continuación, llamar al método EndInvoke.

  • Sondear el resultado IAsyncResult devuelto por BeginInvoke para determinar el momento de finalización de la llamada asincrónica y, a continuación, llamar al método EndInvoke.

  • Pasar un delegado para un método de devolución de llamada a BeginInvoke. El método se ejecuta en un subproceso ThreadPool una vez finalizada la llamada asincrónica. El método de devolución de llamada llama a EndInvoke.

    NoteImportante

    Llame siempre a EndInvoke para finalizar la llamada asincrónica.

Definir el método Test y el delegado asincrónico

En los ejemplos de código siguientes se muestran distintas maneras de llamar al mismo método de larga duración, TestMethod, de forma asincrónica. El método TestMethod muestra un mensaje en la consola para indicar que ha iniciado el procesamiento; después permanece inactivo durante unos segundos y, finalmente, termina. TestMethod tiene un parámetro out con el que muestra cómo se agregan dichos parámetros a las firmas de BeginInvoke y EndInvoke. Los parámetros ref se pueden controlar de manera similar.

En el ejemplo de código siguiente se muestra la definición de TestMethod y el delegado denominado AsyncMethodCaller que se puede utilizar para llamar a TestMethod de forma asincrónica. Para compilar cualquiera de los ejemplos de código, debe incluir las definiciones del método TestMethod y el delegado AsyncMethodCaller.

Visual Basic
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices 

Namespace Examples.AdvancedProgramming.AsynchronousOperations
    Public Class AsyncDemo 
        ' The method to be executed asynchronously.
        Public Function TestMethod(ByVal callDuration As Integer, _
                <Out> ByRef threadId As Integer) As String
            Console.WriteLine("Test method begins.")
            Thread.Sleep(callDuration)
            threadId = Thread.CurrentThread.ManagedThreadId()
            return String.Format("My call time was {0}.", callDuration.ToString())
        End Function
    End Class

    ' The delegate must have the same signature as the method
    ' it will call asynchronously.
    Public Delegate Function AsyncMethodCaller(ByVal callDuration As Integer, _
        <Out> ByRef threadId As Integer) As String
End Namespace
C#
using System;
using System.Threading; 

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncDemo 
    {
        // The method to be executed asynchronously.
        public string TestMethod(int callDuration, out int threadId) 
        {
            Console.WriteLine("Test method begins.");
            Thread.Sleep(callDuration);
            threadId = Thread.CurrentThread.ManagedThreadId;
            return String.Format("My call time was {0}.", callDuration.ToString());
        }
    }
    // The delegate must have the same signature as the method
    // it will call asynchronously.
    public delegate string AsyncMethodCaller(int callDuration, out int threadId);
}

Esperar una llamada asincrónica con EndInvoke

La manera más fácil de ejecutar un método de forma asincrónica consiste en empezar a ejecutarlo llamando al método BeginInvoke del delegado, realizar algo de trabajo en el subproceso principal y, después, llamar al método EndInvoke del delegado. EndInvoke podría bloquear el subproceso de llamada, porque no devuelve ningún resultado hasta que finaliza la llamada asincrónica. Se trata de una buena técnica para utilizarla con operaciones de archivos o de redes, pero como se bloquea en EndInvoke, no debería llamarla desde subprocesos que dan servicio a la interfaz de usuario.

Visual Basic
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices 

Namespace Examples.AdvancedProgramming.AsynchronousOperations
    Public Class AsyncMain 
        Shared Sub Main() 
            ' The asynchronous method puts the thread id here.
            Dim threadId As Integer

            ' Create an instance of the test class.
            Dim ad As New AsyncDemo()

            ' Create the delegate.
            Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
       
            ' Initiate the asynchronous call.
            Dim result As IAsyncResult = caller.BeginInvoke(3000, _
                threadId, Nothing, Nothing)

            Thread.Sleep(0)
            Console.WriteLine("Main thread {0} does some work.", _
                 Thread.CurrentThread.ManagedThreadId)

            ' Call EndInvoke to Wait for the asynchronous call to complete,
            ' and to retrieve the results.
            Dim returnValue As String = caller.EndInvoke(threadId, result)

            Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", _
                threadId, returnValue)
        End Sub
    End Class

End Namespace
C#
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        public static void Main() 
        {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);

            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",
                Thread.CurrentThread.ManagedThreadId);

            // Call EndInvoke to wait for the asynchronous call to complete,
            // and to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

Esperar una llamada asincrónica con WaitHandle

Puede obtener un objeto WaitHandle utilizando la propiedad AsyncWaitHandle de IAsyncResult devuelta por BeginInvoke. WaitHandle se señaliza cuando finaliza la llamada asincrónica y puede esperar a que termine llamando al método WaitOne.

Si utiliza WaitHandle, puede realizar otros procesamientos adicionales antes o después de finalizada la llamada asincrónica, pero antes de llamar al método EndInvoke para recuperar los resultados.

Visual Basic
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices 

Namespace Examples.AdvancedProgramming.AsynchronousOperations

    Public Class AsyncMain 
        Shared Sub Main() 
            ' The asynchronous method puts the thread id here.
            Dim threadId As Integer

            ' Create an instance of the test class.
            Dim ad As New AsyncDemo()

            ' Create the delegate.
            Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
       
            ' Initiate the asynchronous call.
            Dim result As IAsyncResult = caller.BeginInvoke(3000, _
                threadId, Nothing, Nothing)

            Thread.Sleep(0)
            Console.WriteLine("Main thread {0} does some work.", _
                Thread.CurrentThread.ManagedThreadId)
            ' Perform additional processing here and then
            ' wait for the WaitHandle to be signaled.
            result.AsyncWaitHandle.WaitOne()

            ' Call EndInvoke to retrieve the results.
            Dim returnValue As String = caller.EndInvoke(threadId, result)

            Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", _
                threadId, returnValue)
        End Sub
    End Class
End Namespace
C#
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() 
        {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);

            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",
                Thread.CurrentThread.ManagedThreadId);

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

            // Perform additional processing here.
            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

Sondear la finalización de una llamada asincrónica

Puede utilizar la propiedad IsCompleted del objeto IAsyncResult devuelto por BeginInvoke para descubrir el momento en que finaliza la llamada asincrónica. Puede hacer esto último cuando realice la llamada asincrónica desde un subproceso que dé servicio a la interfaz de usuario. Sondear la finalización de una llamada asincrónica permite al subproceso de llamada seguirse ejecutando mientras la llamada asincrónica se ejecuta en un subproceso ThreadPool.

Visual Basic
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices 

Namespace Examples.AdvancedProgramming.AsynchronousOperations

    Public Class AsyncMain 
        Shared Sub Main() 
            ' The asynchronous method puts the thread id here.
            Dim threadId As Integer

            ' Create an instance of the test class.
            Dim ad As New AsyncDemo()

            ' Create the delegate.
            Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
       
            ' Initiate the asynchronous call.
            Dim result As IAsyncResult = caller.BeginInvoke(3000, _
                threadId, Nothing, Nothing)

            ' Poll while simulating work.
            While result.IsCompleted = False
                Thread.Sleep(10)
            End While

            ' Call EndInvoke to retrieve the results.
            Dim returnValue As String = caller.EndInvoke(threadId, result)

            Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", _
                threadId, returnValue)
        End Sub
    End Class
End Namespace
C#
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);

            // Poll while simulating work.
            while(result.IsCompleted == false) {
                Thread.Sleep(10);
            }

            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

Ejecutar un método de devolución de llamada cuando finaliza una llamada asincrónica

Si no es necesario que el subproceso que inicia la llamada asincrónica sea el mismo que procesa los resultados, puede ejecutar un método de devolución de llamada cuando finalice la llamada. El método de devolución de llamada se ejecuta en un subproceso ThreadPool.

Para utilizar un método de devolución de llamada, debe pasar al método BeginInvoke un delegado de AsyncCallback que haga referencia al método de devolución de llamada. También puede pasar un objeto que contenga la información que va a utilizar el método de devolución de llamada. Por ejemplo, puede pasar el delegado que se utilizó para iniciar la llamada, de modo que el método de devolución de llamada puede llamar al método EndInvoke.

Visual Basic
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices 

Namespace Examples.AdvancedProgramming.AsynchronousOperations

    Public Class AsyncMain 
        ' The asynchronous method puts the thread id here.
        Private Shared threadId As Integer
        
        Shared Sub Main() 
            ' Create an instance of the test class.
            Dim ad As New AsyncDemo()

            ' Create the delegate.
            Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
       
            ' Initiate the asynchronous call.
            Dim result As IAsyncResult = caller.BeginInvoke(3000, _
                threadId, _
                AddressOf CallbackMethod, _
                caller)

            Console.WriteLine("Press Enter to close application.")
            Console.ReadLine()
        End Sub

        ' Callback method must have the same signature as the
        ' AsyncCallback delegate.
        Shared Sub CallbackMethod(ByVal ar As IAsyncResult)
            ' Retrieve the delegate.
            Dim caller As AsyncMethodCaller = CType(ar.AsyncState, AsyncMethodCaller)

            ' Call EndInvoke to retrieve the results.
            Dim returnValue As String = caller.EndInvoke(threadId, ar)

            Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", _
                threadId, returnValue)
        End Sub
    End Class
End Namespace
C#
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        // Asynchronous method puts the thread id here.
        private static int threadId;

        static void Main() {
            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.  Include an AsyncCallback
            // delegate representing the callback method, and the data
            // needed to call EndInvoke.
            IAsyncResult result = caller.BeginInvoke(3000,
                out threadId, 
                new AsyncCallback(CallbackMethod),
                caller );

            Console.WriteLine("Press Enter to close application.");
            Console.ReadLine();
        }
        
        // Callback method must have the same signature as the
        // AsyncCallback delegate.
        static void CallbackMethod(IAsyncResult ar) 
        {
            // Retrieve the delegate.
            AsyncMethodCaller caller = (AsyncMethodCaller) ar.AsyncState;

            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, ar);

            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

Vea también

Contenido de la comunidad   ¿Qué es Community Content?
Agregar contenido nuevo RSS  Anotaciones
Processing
© 2009 Microsoft Corporation. Reservados todos los derechos. Términos de uso | Marcas Registradas | Privacidad
Page view tracker