Este artigo foi traduzido por máquina. Para visualizar o arquivo em inglês, marque a caixa de seleção Inglês. Você também pode exibir o texto Em inglês em uma janela pop-up, movendo o ponteiro do mouse sobre o texto.
Tradução
Inglês

Chamando métodos síncronos de forma assíncrona

 

O .NET Framework permite que você chamar qualquer método de maneira assíncrona. Para fazer isso, você define um delegado com a mesma assinatura do método que você deseja chamar; o common language runtime automaticamente define BeginInvoke e EndInvoke métodos para esse delegado, com as assinaturas apropriadas.

System_CAPS_noteObservação

Chama o delegado assíncrono, especificamente o BeginInvoke e EndInvoke métodos, não são suportados no .NET Compact Framework.

O BeginInvoke método inicia a chamada assíncrona. Ela tem os mesmos parâmetros que o método que você deseja executar de forma assíncrona, além de dois parâmetros opcionais adicionais. O primeiro parâmetro é um AsyncCallback representante que referencia um método a ser chamado quando a chamada assíncrona for concluída. O segundo parâmetro é um objeto definido pelo usuário que passa informações para o método de retorno de chamada. BeginInvoke retorna imediatamente e não aguarda a chamada assíncrona seja concluída. BeginInvoke Retorna um IAsyncResult, que pode ser usado para monitorar o progresso da chamada assíncrona.

O EndInvoke método recupera os resultados da chamada assíncrona. Ele pode ser chamado a qualquer momento após a BeginInvoke. Se a chamada assíncrona não for concluída, EndInvoke bloqueia o thread de chamada até que ela seja concluída. Os parâmetros de EndInvoke incluem a out e ref parâmetros (< Out > ByRef e ByRef no Visual Basic) do método que você deseja executar de forma assíncrona, mais o IAsyncResult retornado por BeginInvoke

System_CAPS_noteObservação

O recurso IntelliSense no Visual Studio 2005 exibe os parâmetros de BeginInvoke e EndInvoke. Se você não estiver usando o Visual Studio ou uma ferramenta semelhante, ou se você estiver usando c# com Visual Studio 2005, consulte Modelo de programação assíncrona (APM) para obter uma descrição dos parâmetros definidos para esses métodos.

Os exemplos de código neste tópico demonstram quatro formas comuns de usar BeginInvoke e EndInvoke para fazer chamadas assíncronas. Depois de chamar BeginInvoke pode fazer o seguinte:

  • Alguns trabalhar e, em seguida, chame EndInvoke para bloquear até que a chamada é concluída.

  • Obter um WaitHandle usando o IAsyncResult.AsyncWaitHandle propriedade, use seu WaitOne método para impedir a execução até que o WaitHandle é sinalizado e, em seguida, chame EndInvoke.

  • Pesquisa o IAsyncResult retornado por BeginInvoke para determinar quando a chamada assíncrona for concluída e, em seguida, chame EndInvoke.

  • Passar um delegado para um método de retorno de chamada BeginInvoke. O método é executado em um ThreadPool thread quando a chamada assíncrona for concluída. As chamadas de método de retorno de chamada EndInvoke.

System_CAPS_importantImportante

Não importa qual técnica é usar, sempre chamar EndInvoke para completar a chamada assíncrona.

Os exemplos de código a seguem demonstram várias maneiras de chamar o mesmo método de execução longa, TestMethod, de forma assíncrona. O TestMethod método exibe uma mensagem de console para mostrar que ele começou a processá dormem por alguns segundos e, em seguida, termina. TestMethod tem um out parâmetro para demonstrar o modo esses parâmetros são adicionados às assinaturas de BeginInvoke e EndInvoke. Você pode manipular ref parâmetros da mesma forma.

O exemplo de código a seguir mostra a definição de TestMethod e o delegado chamado AsyncMethodCaller que pode ser usado para chamar TestMethod assincronamente. Para compilar os exemplos de código, você deve incluir as definições de TestMethod e o AsyncMethodCaller delegar.

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

É a maneira mais simples de executar um método de forma assíncrona iniciar a execução do método chamando o delegado BeginInvoke método, alguns trabalhar no thread principal e, em seguida, chamar o delegado EndInvoke método. EndInvoke pode bloquear o thread de chamada porque ela não retorna até que a chamada assíncrona seja concluída. Isso é uma boa técnica para usar com operações de arquivo ou de rede.

System_CAPS_importantImportante

Como EndInvoke podem bloquear, você nunca deve chamá-lo de threads que a interface do usuário do serviço.

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

/* This example produces output similar to the following:

Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
 */

Você pode obter um WaitHandle usando o AsyncWaitHandle propriedade o IAsyncResult retornado por BeginInvoke. O WaitHandle é sinalizado quando a chamada assíncrona é concluída, e você pode esperar para ele chamando o WaitOne método.

Se você usar um WaitHandle, você pode executar processamento adicional antes ou após a chamada assíncrona, mas antes de chamar EndInvoke para recuperar os resultados.

System_CAPS_noteObservação

O identificador de espera não é fechado automaticamente quando você chama EndInvoke. Se você liberar todas as referências para o identificador de espera, recursos do sistema são liberados quando a coleta de lixo recupera o identificador de espera. Para liberar recursos do sistema assim que terminar de usar o identificador de espera, descartá-lo ao chamar o WaitHandle.Close método. Coleta de lixo funciona com mais eficiência quando objetos descartáveis.

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);

            // Close the wait handle.
            result.AsyncWaitHandle.Close();

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

/* This example produces output similar to the following:

Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
 */

Você pode usar o IsCompleted propriedade o IAsyncResult retornado por BeginInvoke para descobrir quando a chamada assíncrona for concluída. Você pode fazer isso ao fazer a chamada assíncrona de um thread que a interface do usuário de serviços. Sondagem para conclusão permite que o thread de chamada continuar executando enquanto a chamada assíncrona está sendo executado em um ThreadPool thread.

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(250);
                Console.Write(".");
            }

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

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

/* This example produces output similar to the following:

Test method begins.
.............
The call executed on thread 3, with return value "My call time was 3000.".
 */

Se o segmento que inicia a chamada assíncrona não precisa ser o thread que processa os resultados, você pode executar um método de retorno de chamada quando a chamada é concluída. O método de retorno de chamada é executado em um ThreadPool thread.

Para usar um método de retorno de chamada, você deve passar BeginInvoke um AsyncCallback delegado que representa o método de retorno de chamada. Você também pode passar um objeto que contém as informações a serem usadas pelo método de retorno de chamada. No método de retorno de chamada, você pode converter o IAsyncResult, que é o único parâmetro do método de retorno de chamada, como um AsyncResult objeto. Você pode usar o AsyncResult.AsyncDelegate propriedade para obter o delegado que foi usado para iniciar a chamada para que você possa chamar EndInvoke.

Observações sobre o exemplo:

  • O threadId parâmetro TestMethod é um out parâmetro (< Out > ByRef no Visual Basic), portanto, o valor de entrada nunca é usado pelos TestMethod Uma variável fictícia é passada para o BeginInvoke chamar. Se o threadId parâmetro foram um ref parâmetro (ByRef no Visual Basic), a variável precisa ser um campo de nível de classe para que ele pode ser passado para ambos os BeginInvoke e EndInvoke.

  • As informações de estado que são passadas para BeginInvoke é uma cadeia de caracteres de formato, que usa o método de retorno de chamada para formatar uma mensagem de saída. Porque ela é passada como tipo Object, as informações de estado devem ser convertidas para o tipo correto antes de ser usada.

  • O retorno de chamada é feito em um ThreadPool thread. ThreadPool threads são threads em segundo plano, o que não manter o aplicativo em execução se o thread principal termina, então o thread principal do exemplo precisa dormir tempo suficiente para o retorno de chamada concluir.

using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() 
        {
            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            // The threadId parameter of TestMethod is an out parameter, so
            // its input value is never used by TestMethod. Therefore, a dummy
            // variable can be passed to the BeginInvoke call. If the threadId
            // parameter were a ref parameter, it would have to be a class-
            // level field so that it could be passed to both BeginInvoke and 
            // EndInvoke.
            int dummy = 0;

            // Initiate the asynchronous call, passing three seconds (3000 ms)
            // for the callDuration parameter of TestMethod; a dummy variable 
            // for the out parameter (threadId); the callback delegate; and
            // state information that can be retrieved by the callback method.
            // In this case, the state information is a string that can be used
            // to format a console message.
            IAsyncResult result = caller.BeginInvoke(3000,
                out dummy, 
                new AsyncCallback(CallbackMethod),
                "The call executed on thread {0}, with return value \"{1}\".");

            Console.WriteLine("The main thread {0} continues to execute...", 
                Thread.CurrentThread.ManagedThreadId);

            // The callback is made on a ThreadPool thread. ThreadPool threads
            // are background threads, which do not keep the application running
            // if the main thread ends. Comment out the next line to demonstrate
            // this.
            Thread.Sleep(4000);

            Console.WriteLine("The main thread ends.");
        }

        // The callback method must have the same signature as the
        // AsyncCallback delegate.
        static void CallbackMethod(IAsyncResult ar) 
        {
            // Retrieve the delegate.
            AsyncResult result = (AsyncResult) ar;
            AsyncMethodCaller caller = (AsyncMethodCaller) result.AsyncDelegate;

            // Retrieve the format string that was passed as state 
            // information.
            string formatString = (string) ar.AsyncState;

            // Define a variable to receive the value of the out parameter.
            // If the parameter were ref rather than out then it would have to
            // be a class-level field so it could also be passed to BeginInvoke.
            int threadId = 0;

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

            // Use the format string to format the output message.
            Console.WriteLine(formatString, threadId, returnValue);
        }
    }
}

/* This example produces output similar to the following:

The main thread 1 continues to execute...
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
The main thread ends.
 */
Mostrar: