异步编程概述

转载 2006年05月19日 12:26:00

使用 .NET 异步编程,在程序继续执行的同时对 .NET 类方法进行调用,直到进行指定的回调为止;或者如果没有提供回调,则直到对调用的阻塞、轮询或等待完成为止。例如,一个程序可以调用一个方法,该方法枚举一个较大的列表,同时主程序将继续执行。在完成枚举后,进行回调并由程序对它进行寻址。

异步编程是由 .NET Framework 的许多区域支持的功能,这些区域包括:

  • 文件 IO、流 IO、套接字 IO
  • 网络:HTTP、TCP
  • 远程处理信道(HTTP、TCP)和代理
  • 使用 ASP.NET 创建的 XML Web services
  • ASP.NET Web 窗体
  • 使用 MessageQueue 类的消息队列
  • 异步委托

本节内容

异步编程概述
提供代码示例,演示异步调用普通同步方法的四种方式。
异步编程设计模式
讨论异步设计模式,这些设计模式提供有效和一致的编程模型来处理异步操作。
异步委托
描述异步委托,这些异步委托提供以异步方式调用同步方法的能力。

相关章节

AsyncCallback 委托
讨论 AsyncCallback 委托编程参考。

------------------------------------------------------------------------------------------------------------------------------------

NET Framework 允许您异步调用任何方法。定义与您需要调用的方法具有相同签名的委托;公共语言运行库将自动为该委托定义具有适当签名的 BeginInvokeEndInvoke 方法。

BeginInvoke 方法用于启动异步调用。它与您需要异步执行的方法具有相同的参数,只不过还有两个额外的参数(将在稍后描述)。BeginInvoke 立即返回,不等待异步调用完成。BeginInvoke 返回 IasyncResult,可用于监视调用进度。

EndInvoke 方法用于检索异步调用结果。调用 BeginInvoke 后可随时调用 EndInvoke 方法;如果异步调用未完成,EndInvoke 将一直阻塞到异步调用完成。EndInvoke 的参数包括您需要异步执行的方法的 outref 参数(在 Visual Basic 中为 <Out> ByRefByRef)以及由 BeginInvoke 返回的 IAsyncResult

注意   Visual Studio .NET 中的智能感知功能会显示 BeginInvokeEndInvoke 的参数。如果您没有使用 Visual Studio 或类似的工具,或者您使用的是 C# 和 Visual Studio .NET,请参见异步方法签名获取有关运行库为这些方法定义的参数的描述。

本主题中的代码演示了四种使用 BeginInvokeEndInvoke 进行异步调用的常用方法。调用了 BeginInvoke 后,可以:

  • 进行某些操作,然后调用 EndInvoke 一直阻塞到调用完成。
  • 使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出 WaitHandle 信号,然后调用 EndInvoke
  • 轮询由 BeginInvoke 返回的 IAsyncResult,确定异步调用何时完成,然后调用 EndInvoke
  • 将用于回调方法的委托传递给 BeginInvoke。该方法在异步调用完成后在 ThreadPool 线程上执行,它可以调用 EndInvoke
    警告   始终在异步调用完成后调用 EndInvoke

测试方法和异步委托

四个示例全部使用同一个长期运行的测试方法 TestMethod。该方法显示一个表明它已开始处理的控制台信息,休眠几秒钟,然后结束。TestMethod 有一个 out 参数(在 Visual Basic 中为 <Out> ByRef),它演示了如何将这些参数添加到 BeginInvokeEndInvoke 的签名中。您可以用类似的方式处理 ref 参数(在 Visual Basic 中为 ByRef)。

下面的代码示例显示 TestMethod 以及代表 TestMethod 的委托;若要使用任一示例,请将示例代码追加到这段代码中。

注意   为了简化这些示例,TestMethod 在独立于 Main() 的类中声明。或者,TestMethod 可以是包含 Main() 的同一类中的 static 方法(在 Visual Basic 中为 Shared)。
[Visual Basic]
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices 

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 = AppDomain.GetCurrentThreadId()
        return "MyCallTime was " + callDuration.ToString()
    End Function
End Class

' The delegate must have the same signature as the method
' you want to call asynchronously.
Public Delegate Function AsyncDelegate(ByVal callDuration As Integer, _
    <Out> ByRef threadId As Integer) As String
[C#]
using System;
using System.Threading; 

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 = AppDomain.GetCurrentThreadId();
        return "MyCallTime was " + callDuration.ToString();
    }
}

// The delegate must have the same signature as the method
// you want to call asynchronously.
public delegate string AsyncDelegate(int callDuration, out int threadId);

使用 EndInvoke 等待异步调用

异步执行方法的最简单方式是以 BeginInvoke 开始,对主线程执行一些操作,然后调用 EndInvokeEndInvoke 直到异步调用完成后才返回。这种技术非常适合文件或网络操作,但是由于它阻塞 EndInvoke,所以不要从用户界面的服务线程中使用它。

[Visual Basic]
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 dlgt As New AsyncDelegate(AddressOf ad.TestMethod)
   
        ' Initiate the asynchronous call.
        Dim ar As IAsyncResult = dlgt.BeginInvoke(3000, _
            threadId, Nothing, Nothing)

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

        ' Call EndInvoke to Wait for the asynchronous call to complete,
        ' and to retrieve the results.
        Dim ret As String = dlgt.EndInvoke(threadId, ar)

        Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", threadId, ret)
    End Sub
End Class
[C#]
public class AsyncMain {
    static void Main(string[] args) {
        // The asynchronous method puts the thread id here.
        int threadId;

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

        // Create the delegate.
        AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
   
        // Initiate the asychronous call.
        IAsyncResult ar = dlgt.BeginInvoke(3000, 
            out threadId, null, null);

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

        // Call EndInvoke to Wait for the asynchronous call to complete,
        // and to retrieve the results.
        string ret = dlgt.EndInvoke(out threadId, ar);

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

使用 WaitHandle 等待异步调用

等待 WaitHandle 是一项常用的线程同步技术。您可以使用由 BeginInvoke 返回的 IAsyncResultAsyncWaitHandle 属性来获取 WaitHandle。异步调用完成时会发出 WaitHandle 信号,而您可以通过调用它的 WaitOne 等待它。

如果您使用 WaitHandle,则在异步调用完成之后,但在通过调用 EndInvoke 检索结果之前,可以执行其他处理。

[Visual Basic]
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 dlgt As New AsyncDelegate(AddressOf ad.TestMethod)
   
        ' Initiate the asynchronous call.
        Dim ar As IAsyncResult = dlgt.BeginInvoke(3000, 
            threadId, Nothing, Nothing)

        Thread.Sleep(0)
        Console.WriteLine("Main thread {0} does some work.",
            AppDomain.GetCurrentThreadId())

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

        ' Perform additional processing here.
        ' Call EndInvoke to retrieve the results.
        Dim ret As String = dlgt.EndInvoke(threadId, ar)

        Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", threadId, ret)
    End Sub
End Class
[C#]
public class AsyncMain {
    static void Main(string[] args) {
        // The asynchronous method puts the thread id here.
        int threadId;

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

        // Create the delegate.
        AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
   
        // Initiate the asychronous call.
        IAsyncResult ar = dlgt.BeginInvoke(3000, 
            out threadId, null, null);

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

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

        // Perform additional processing here.
        // Call EndInvoke to retrieve the results.
        string ret = dlgt.EndInvoke(out threadId, ar);

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

轮询异步调用完成

您可以使用由 BeginInvoke 返回的 IAsyncResultIsCompleted 属性来发现异步调用何时完成。从用户界面的服务线程中进行异步调用时可以执行此操作。轮询完成允许用户界面线程继续处理用户输入。

[Visual Basic]
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 dlgt As New AsyncDelegate(AddressOf ad.TestMethod)
   
        ' Initiate the asynchronous call.
        Dim ar As IAsyncResult = dlgt.BeginInvoke(3000, 
            threadId, Nothing, Nothing)

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

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

        Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", threadId, ret)
    End Sub
End Class
[C#]
public class AsyncMain {
    static void Main(string[] args) {
        // The asynchronous method puts the thread id here.
        int threadId;

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

        // Create the delegate.
        AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
   
        // Initiate the asychronous call.
        IAsyncResult ar = dlgt.BeginInvoke(3000, 
            out threadId, null, null);

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

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

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

异步调用完成时执行回调方法

如果启动异步调用的线程不需要处理调用结果,则可以在调用完成时执行回调方法。回调方法在 ThreadPool 线程上执行。

要使用回调方法,必须将代表该方法的 AsyncCallback 委托传递给 BeginInvoke。也可以传递包含回调方法将要使用的信息的对象。例如,可以传递启动调用时曾使用的委托,以便回调方法能够调用 EndInvoke

[Visual Basic]
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 dlgt As New AsyncDelegate(AddressOf ad.TestMethod)
   
        ' Initiate the asynchronous call.
        Dim ar As IAsyncResult = dlgt.BeginInvoke(3000, _
            threadId, _
            AddressOf CallbackMethod, _
            dlgt)

        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 dlgt As AsyncDelegate = CType(ar.AsyncState, AsyncDelegate)

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

        Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", threadId, ret)
    End Sub
End Class
[C#]
public class AsyncMain {
    // Asynchronous method puts the thread id here.
    private static int threadId;

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

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

        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.
        AsyncDelegate dlgt = (AsyncDelegate) ar.AsyncState;

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

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

相关文章推荐

C#异步编程模式IAsyncResult概述

IAsyncResult 异步设计模式通过名为 BeginOperationName 和 EndOperationName 的两个方法来实现原同步方法的异步调用,如 FileStream 类提供了 B...

异步编程:线程概述及使用

作者:滴答的雨(何雨泉) 转自:http://www.cnblogs.com/heyuquan/archive/2012/12/16/2820775.html 异步编程:线程概述及使用   ...
  • whw8007
  • whw8007
  • 2014年02月27日 13:11
  • 527

Javascript异步编程

  • 2017年11月16日 10:01
  • 6.52MB
  • 下载

JavaScript异步编程(Windows8)

  • 2012年12月20日 19:22
  • 25KB
  • 下载

深入浅出nodejs学习笔记--第四章 异步编程

深入浅出nodejs学习笔记--第四章 异步编程 简单介绍了函数式编程,异步编程优势与难点,异步编程的实现方案...

JavaScript异步编程.pdf

  • 2017年06月20日 21:04
  • 6.62MB
  • 下载

Windows并发&异步编程(1)JAVA&多线程

本文在基于C/C++/Windows相关知识的基础上,初步封装一个像JAVA一样的多线程类–Win32Thread。使操作线程能像JAVA一样两步搞定。...

java android业务异步编程小技巧

  • 2014年09月18日 14:14
  • 1.66MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:异步编程概述
举报原因:
原因补充:

(最多只允许输入30个字)