异步编程概述

转载 2006年05月24日 16:21:00

.NET Framework 允许您异步调用任何方法。定义与您需要调用的方法具有相同签名的委托;公共语言运行库将自动为该委托定义具有适当签名的 BeginInvoke 和 EndInvoke 方法。
BeginInvoke 方法用于启动异步调用。它与您需要异步执行的方法具有相同的参数,只不过还有两个额外的参数(将在稍后描述)。BeginInvoke 立即返回,不等待异步调用完成。BeginInvoke 返回 IasyncResult,可用于监视调用进度。
EndInvoke 方法用于检索异步调用结果。调用 BeginInvoke 后可随时调用 EndInvoke 方法;如果异步调用未完成,EndInvoke 将一直阻塞到异步调用完成。EndInvoke 的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。
注意   Visual Studio .NET 中的智能感知功能会显示 BeginInvoke 和 EndInvoke 的参数。如果您没有使用 Visual Studio 或类似的工具,或者您使用的是 C# 和 Visual Studio .NET,请参见异步方法签名获取有关运行库为这些方法定义的参数的描述。
本主题中的代码演示了四种使用 BeginInvoke 和 EndInvoke 进行异步调用的常用方法。调用了 BeginInvoke 后,可以:
进行某些操作,然后调用 EndInvoke 一直阻塞到调用完成。
使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出 WaitHandle 信号,然后调用 EndInvoke。
轮询由 BeginInvoke 返回的 IAsyncResult,确定异步调用何时完成,然后调用 EndInvoke。
将用于回调方法的委托传递给 BeginInvoke。该方法在异步调用完成后在 ThreadPool 线程上执行,它可以调用 EndInvoke。
警告   始终在异步调用完成后调用 EndInvoke。
测试方法和异步委托
四个示例全部使用同一个长期运行的测试方法 TestMethod。该方法显示一个表明它已开始处理的控制台信息,休眠几秒钟,然后结束。TestMethod 有一个 out 参数(在 Visual Basic 中为 <Out> ByRef),它演示了如何将这些参数添加到 BeginInvoke 和 EndInvoke 的签名中。您可以用类似的方式处理 ref 参数(在 Visual Basic 中为 ByRef)。
下面的代码示例显示 TestMethod 以及代表 TestMethod 的委托;若要使用任一示例,请将示例代码追加到这段代码中。
注意   为了简化这些示例,TestMethod 在独立于 Main() 的类中声明。或者,TestMethod 可以是包含 Main() 的同一类中的 static 方法(在 Visual Basic 中为 Shared)。

[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 开始,对主线程执行一些操作,然后调用 EndInvoke。EndInvoke 直到异步调用完成后才返回。这种技术非常适合文件或网络操作,但是由于它阻塞 EndInvoke,所以不要从用户界面的服务线程中使用它。

[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 返回的 IAsyncResult 的 AsyncWaitHandle 属性来获取 WaitHandle。异步调用完成时会发出 WaitHandle 信号,而您可以通过调用它的 WaitOne 等待它。
如果您使用 WaitHandle,则在异步调用完成之后,但在通过调用 EndInvoke 检索结果之前,可以执行其他处理。

[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 返回的 IAsyncResult 的 IsCompleted 属性来发现异步调用何时完成。从用户界面的服务线程中进行异步调用时可以执行此操作。轮询完成允许用户界面线程继续处理用户输入。

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

异步编程概述

.NET Framework 允许您异步调用任何方法。定义与您需要调用的方法具有相同签名的委托;公共语言运行库将自动为该委托定义具有适当签名的 BeginInvoke 和 EndInvoke 方法。B...
  • cxzhq2002
  • cxzhq2002
  • 2008年02月13日 11:29
  • 297

异步编程优势难点及解决方案

异步I/O和非阻塞I/O的区别: 阻塞造成CPU等待I/O,浪费等待时间,非阻塞I/O跟阻塞I/O的差别为调用之后会立即返回。 非阻塞的问题是由于完整的I/O并没有完成,立即返回的并不是业务期望的数据...
  • zsr251
  • zsr251
  • 2015年11月20日 17:50
  • 1139

《深入浅出Node.js》学习笔记——(四)异步编程

Node能够迅速成功并流行的原因: ①V8和异步I/O带来的性能提升 ②前后端JavaScript编程风格一致   4.1 函数式编程 4.1.1高阶函数 可以将函数作为参数,或是作为返...
  • oEternalFlame
  • oEternalFlame
  • 2016年05月30日 20:54
  • 1258

深入理解 Python 异步编程

原文地址:点击打开链接 来源:阿驹(微信公号:驹说码事)  如有好文章投稿,请点击 → 这里了解详情 前言 很多朋友对异步编程都...
  • QH_JAVA
  • QH_JAVA
  • 2017年09月03日 18:06
  • 558

详解JavaScript异步编程技术

详解JavaScript异步编程技术基于浏览器的事件轮询机制(以及Node.js中的事件轮询机制),JavaScript常常会运行在异步环境中。由于JavaScript本身语言的特性(不需要程序员操控...
  • yuhk231
  • yuhk231
  • 2017年02月08日 17:30
  • 1737

PHP异步编程

网页链接 ,来让让大家从比较高的层面了解ZanPHP框架的一些内幕技术。 , 网页链接 ,从底层I/O模型和C语言的扩展实现层面为大家进行技术解密。 , 网页链接 ,从编译器的角度带领...
  • ivan820819
  • ivan820819
  • 2017年06月13日 17:02
  • 409

小试ES6:异步编程之Generator

生成器是es6原生提供的异步编程方案,其语法行为和传统函数完全不同,本文主要通过一些代码示例来记录和总结生成器的用法...
  • jashawn
  • jashawn
  • 2016年09月04日 15:21
  • 206

C#异步编程基础入门总结

异步这概念刚开始接触的时候,不是那么容易接受,但是需要用的地方还真的挺多的,刚学习的时候,也很懵逼走了不少弯路,所以这里有必要总结一下。...
  • kebi007
  • kebi007
  • 2017年08月23日 15:54
  • 1750

Win8.1应用开发之异步编程

在win8应用商店开发时,我们会遇到许多异步方法,它们存在的目的就是为了确保你的应用在执行需要大量时间的任务时仍能保持良好的响应,也就是说调用异步API是为了响应用户的操作。设想一下我们点击一个But...
  • BlueCloudMatrix
  • BlueCloudMatrix
  • 2014年07月08日 22:22
  • 1110

C# 并行编程 之 异步编程模型

异步编程模型的使用
  • wangzhiyu1980
  • wangzhiyu1980
  • 2015年06月17日 09:21
  • 1097
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:异步编程概述
举报原因:
原因补充:

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