异步调用 (转载)

异步操作通常用于执行完成时间可能较长的任务,如打开大文件、连接远程计算机或查询数据库。异步操作在主应用程序线程以外的线程中执行。应用程序调用方法异步执行某个操作时,应用程序可在异步方法执行其任务时继续执行。

.NET框架能够对任何方法进行异步调用。进行异步调用时,需要定义与异步调用的方法具有相同签名的委托。公共语言运行时会自动使用适当的签名为该委托定义BeginInvokeEndInvoke方法。

BeginInvoke方法用于启动异步调用。它与需要异步执行的方法具有相同的参数。此外,它还有两个可选参数。第一个参数是一个AsyncCallback委托,该委托引用在异步调用完成时要调用的方法。第二个参数是一个用户定义的对象,该对象可向回调方法传递数据。BeginInvoke立即返回,不会等待异步调用完成,被调用的方法将在线程池线程中执行。因此,提交请求的原始线程与执行异步方法的线程池线程是并行执行的。BeginInvoke会返回一个IAsyncResult对象,可以使用该对象来监视异步调用进度,也可将该对象传递给EndInvoke方法,以获取异步执行的方法的返回值。

EndInvoke方法用于检索异步调用的结果。调用BeginInvoke方法后可随时调用EndInvoke方法;如果异步调用尚未完成,EndInvoke方法将一直阻塞调用线程,直到异步调用完成后才允许调用线程执行。EndInvoke方法的参数包括需要异步执行的方法的outref参数,以及由BeginInvoke返回的IAsyncResult对象。因此,通过EndInvoke方法可以获得异步调用的方法的所有输出数据,包括返回值、outref参数。

AsyncCallback委托表示在异步操作完成时调用的回调方法,其定义如下:

public delegate void AsyncCallback(IAsyncResult ar);

System.IAsyncResult接口表示异步操作的状态。IAsyncResult接口由包含可异步操作的方法的类实现。它是启动异步操作的方法的返回类型,也是结束异步操作的方法的第三个参数的类型。当异步操作完成时,IAsyncResult对象也将传递给由AsyncCallback委托调用的方法。支持IAsyncResult接口的对象存储异步操作的状态信息,并提供同步对象以允许线程在操作完成时终止。IAsyncResult接口定义了四个公开属性,通过它们可以获取异步调用的状态。

—  AsyncState:获取用户定义的对象,它限定或包含关于异步操作的信息。

—  AsyncWaitHandle:获取用于等待异步操作完成的 WaitHandle

—  CompletedSynchronously:获取异步操作是否同步完成的指示。

—  IsCompleted:获取异步操作是否已完成的指示。

使用BeginInvokeEndInvoke进行异步调用的常用方法主要有四种:

调用BeginInvoke方法启动异步方法,进行某些操作,然后调用EndInvoke方法来一直阻止请求线程到调用完成。

调用BeginInvoke方法启动异步方法,使用System.IAsyncResult.AsyncWaitHandle属性获取WaitHandle,使用它的WaitOne方法一直阻止执行直到发出WaitHandle信号,然后调用EndInvoke方法。

调用BeginInvoke方法启动异步方法,轮询由BeginInvoke返回的IAsyncResult,确定异步调用何时完成,然后调用EndInvoke

调用BeginInvoke方法启动异步方法时,将代表异步方法完成时需要回调的方法的委托传递给BeginInvoke。异步调用完成后,将在ThreadPool线程上执行该回调方法。在该回调方法中调用EndInvoke

每种方法都是通过BeginInvoke方法来启动异步方法,调用EndInvoke方法来完成异步调用。

1.直接调用EndInvoke 方法等待异步调用结束

异步执行方法的最简单的方式是通过调用委托的BeginInvoke方法来开始执行方法,在主线程上执行一些工作,然后调用委托的EndInvoke方法。EndInvoke可能会阻止调用线程,因为它直到异步调用完成之后才返回。这种技术非常适合于文件或网络操作,但是由于EndInvoke会阻止它,所以不要从服务于用户界面的线程中调用它。

下面的代码说明了如何使用这种方法来进行异步调用,并获得异步方法的结果:

// AsynCall1.cs

// 异步调用示例: 直接调用EndInvoke 方法等待异步调用结束

using System;

using System.Threading;

// 定义异步调用方法的委托

// 它的签名必须与要异步调用的方法一致

public delegate int AsynComputeCaller(ulong l, out ulong factorial);

public class Factorial

{

    // 计算阶乘

    public ulong Compute(ulong l)

    {

        // 不要太快 :-)

        Thread.Sleep(50);

        if (l == 1)

        {

            return 1;

        }

        else

        {

            return l * Compute(l - 1);

        }

    }

    // 要异步调用的方法

    // 1. 调用Factorial方法来计算阶乘,并用out参数返回

    // 2. 统计计算阶乘所用的时间,并返回该值

    public int AsynCompute(ulong l, out ulong factorial)

    {

        Console.WriteLine("开始异步方法");

       

        DateTime startTime = DateTime.Now;

        factorial = Compute(l);

        TimeSpan usedTime =

                      new TimeSpan(DateTime.Now.Ticks - startTime.Ticks);

       

        Console.WriteLine("结束异步方法");

        return usedTime.Milliseconds;

    }

}

public class Test

{

    public static void Main()

    {

        // 创建包含异步方法的类的实例

        Factorial fact = new Factorial();

        // 创建异步委托

        AsynComputeCaller caller = new AsynComputeCaller(fact.AsynCompute);

        Console.WriteLine("启动异步调用");

        ulong l = 30;

        ulong lf;

        // 启动异步调用

        IAsyncResult result = caller.BeginInvoke(l, out lf, null, null);

        // 主线程进行一些操作

        Thread.Sleep(0);

        Console.WriteLine("主线程进行一些操作");

        // 调用EndInvoke来等待异步调用结束,并获得结果

        int returnValue = caller.EndInvoke(out lf, result);

        // 异步调用的方法已经结束,显示结果

        Console.WriteLine("已经得到结果:{0}的阶乘为{1},计算时间为{2}毫秒",

                               l, lf, returnValue);

    }

}

2.使用 WaitHandle 等待异步调用结束

可以使用BeginInvoke方法返回的IAsyncResultAsyncWaitHandle属性来获取WaitHandle。异步调用完成时会发出WaitHandle信号,可以通过调用WaitOne方法来等待它。

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

下面的代码说明了如何使用这种方法来进行异步调用,并获得异步方法的结果:

// AsynCall2.cs

// 异步调用示例:使用 WaitHandle 等待异步调用结束

using System;

using System.Threading;

// 定义异步调用方法的委托

// 它的签名必须与要异步调用的方法一致

public delegate int AsynComputeCaller(ulong l, out ulong factorial);

public class Factorial

{

    // 计算阶乘

    public ulong Compute(ulong l)

    {

        // 不要太快 :-)

        Thread.Sleep(50);

        if (l == 1)

        {

            return 1;

        }

        else

        {

            return l * Compute(l - 1);

        }

    }

    // 要异步调用的方法

    // 1. 调用Factorial方法来计算阶乘,并用out参数返回

    // 2. 统计计算阶乘所用的时间,并返回该值

    public int AsynCompute(ulong l, out ulong factorial)

    {

        Console.WriteLine("开始异步方法");

       

        DateTime startTime = DateTime.Now;

        factorial = Compute(l);

        TimeSpan usedTime =

                        new TimeSpan(DateTime.Now.Ticks - startTime.Ticks);

       

        Console.WriteLine("结束异步方法");

        return usedTime.Milliseconds;

    }

}

public class Test

{

    public static void Main()

    {

        // 创建包含异步方法的类的实例

        Factorial fact = new Factorial();

        // 创建异步委托

        AsynComputeCaller caller = new AsynComputeCaller(fact.AsynCompute);

        Console.WriteLine("启动异步调用");

        ulong l = 30;

        ulong lf;

        // 启动异步调用

        IAsyncResult result = caller.BeginInvoke(l, out lf, null, null);

        // 主线程进行一些操作

        Thread.Sleep(0);

        Console.WriteLine("主线程进行一些操作");

        // 等待WaitHandle接收到信号

        Console.WriteLine("等待WaitHandle接收到信号");

        result.AsyncWaitHandle.WaitOne();

        // 主线程进行一些操作

        Thread.Sleep(0);

        Console.WriteLine("异步方法已经结束,主线程进行另外一些操作");

        // 调用EndInvoke来获得结果

        int returnValue = caller.EndInvoke(out lf, result);

        // 异步调用的方法已经结束,显示结果

        Console.WriteLine("{0}的阶乘为{1},计算时间为{2}毫秒",

                              l, lf, returnValue);

    }

}

3.轮询异步调用是否完成

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

下面的代码说明了如何使用这种方法来进行异步调用,并获得异步方法的结果:

// AsynCall3.cs

// 异步调用示例: 轮询异步调用是否完成

using System;

using System.Threading;

// 定义异步调用方法的委托

// 它的签名必须与要异步调用的方法一致

public delegate int AsynComputeCaller(ulong l, out ulong factorial);

public class Factorial

{

    // 计算阶乘

    public ulong Compute(ulong l)

    {

        // 不要太快 :-)

        Thread.Sleep(50);

        if (l == 1)

        {

            return 1;

        }

        else

        {

            return l * Compute(l - 1);

        }

    }

    // 要异步调用的方法

    // 1. 调用Factorial方法来计算阶乘,并用out参数返回

    // 2. 统计计算阶乘所用的时间,并返回该值

    public int AsynCompute(ulong l, out ulong factorial)

    {

        Console.WriteLine("开始异步方法");

       

        DateTime startTime = DateTime.Now;

        factorial = Compute(l);

        TimeSpan usedTime =

                               new TimeSpan(DateTime.Now.Ticks - startTime.Ticks);

       

        Console.WriteLine("\n结束异步方法");

        return usedTime.Milliseconds;

    }

}

public class Test

{

    public static void Main()

    {

        // 创建包含异步方法的类的实例

        Factorial fact = new Factorial();

        // 创建异步委托

        AsynComputeCaller caller = new AsynComputeCaller(fact.AsynCompute);

        Console.WriteLine("启动异步调用");

        ulong l = 30;

        ulong lf;

        // 启动异步调用

        IAsyncResult result = caller.BeginInvoke(l, out lf, null, null);

        // 轮询异步方法是否结束

        Console.WriteLine("主线程进行一些操作");

        while (result.IsCompleted == false)

        {

            // 主线程进行一些操作

            Thread.Sleep(10);

            Console.Write(".");

        }

        // 主线程进行一些操作

        Thread.Sleep(0);

        Console.WriteLine("异步方法已经结束,主线程进行另外一些操作");

        // 调用EndInvoke来获得结果

        int returnValue = caller.EndInvoke(out lf, result);

        // 异步调用的方法已经结束,显示结果

        Console.WriteLine("已经得到结果:{0}的阶乘为{1},计算时间为{2}毫秒",

                               l, lf, returnValue);

    }

}

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

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

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

下面的代码说明了如何使用这种方法来进行异步调用,并获得异步方法的结果:

// AsynCall4.cs

// 异步调用示例: 在异步调用完成时执行回调方法

using System;

using System.Threading;

// 定义异步调用方法的委托

// 它的签名必须与要异步调用的方法一致

public delegate int AsynComputeCaller(ulong l, out ulong factorial);

public class Factorial

{

    // 计算阶乘

    public ulong Compute(ulong l)

    {

        // 不要太快 :-)

        Thread.Sleep(50);

        if (l == 1)

        {

            return 1;

        }

        else

        {

            return l * Compute(l - 1);

        }

    }

    // 要异步调用的方法

    // 1. 调用Factorial方法来计算阶乘,并用out参数返回

    // 2. 统计计算阶乘所用的时间,并返回该值

    public int AsynCompute(ulong l, out ulong factorial)

    {

        Console.WriteLine("开始异步方法");

       

        DateTime startTime = DateTime.Now;

        factorial = Compute(l);

        TimeSpan usedTime =

                               new TimeSpan(DateTime.Now.Ticks - startTime.Ticks);

       

        Console.WriteLine("结束异步方法");

        return usedTime.Milliseconds;

    }

}

public class Test

{

    static ulong l = 30;

    static ulong lf;

    public static void Main()

    {

        // 创建包含异步方法的类的实例

        Factorial fact = new Factorial();

        // 创建异步委托

        AsynComputeCaller caller = new AsynComputeCaller(fact.AsynCompute);

        // 启动异步调用

        Console.WriteLine("启动异步调用");

        IAsyncResult result = caller.BeginInvoke(l, out lf,

                                new AsyncCallback(CallbackMethod), caller);

        // 主线程进行一些操作

        Thread.Sleep(0);

        Console.WriteLine("主线程进行一些操作");

        Console.WriteLine("Enter键结束程序...");

        Console.ReadLine();

    }

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

    // 该回调方法的签名必须与AsyncCallback委托一致

    static void CallbackMethod(IAsyncResult ar)

    {

        // 获取委托

        AsynComputeCaller caller = (AsynComputeCaller)ar.AsyncState;

        // 调用EndInvoke来获得结果

        int returnValue = caller.EndInvoke(out lf, ar);

        // 异步调用的方法已经结束,显示结果

        Console.WriteLine("已经得到结果:{0}的阶乘为{1},计算时间为{2}毫秒",

                               l, lf, returnValue);

    }

}

转载于:https://www.cnblogs.com/vincedotnet/archive/2007/09/04/881045.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363923.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《Effective Java》读书笔记 Item 1:考虑静态工厂方法,而不是构造器

众所周知,要想能获取一个类的实例,该类得要提供一个public的构造器。但是《Effective Java》书中说还有一个方法,那就是提供静态工厂方法(static factory method),该方法时静态,同时可以根据参数…

[转]MySQL 表锁和行锁机制

本文转自:http://www.cnblogs.com/itdragon/p/8194622.html MySQL 表锁和行锁机制 行锁变表锁,是福还是坑?如果你不清楚MySQL加锁的原理,你会被它整的很惨!不知坑在何方?没事,我来给你们标记几个…

使用JS实现文字搬运工

使用JS实现文字搬运工 效果图&#xff1a; 代码如下&#xff0c;复制即可使用&#xff1a; <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <title>使用JS实现文字搬运工&…

ActiveMQ –经纪人网络解释–第3部分

现在&#xff0c;我们已经在本博客系列的第1部分和第2 部分中了解了ActiveMQ网络连接器的基础&#xff0c;在第3部分中&#xff0c;我们将研究ActiveMQ如何平衡连接到代理网络的使用者。 介绍 当可以无序处理队列中的消息时通常使用并发使用者&#xff0c;通常可以提高消息吞吐…

PJMEDIA之录音器的使用(capture sound to avi file)

为了熟悉pjmedia的相关函数以及使用方法&#xff0c;这里练习了官网上的一个录音器的例子。 核心函数&#xff1a; pj_status_t pjmedia_wav_writer_port_create(pj_pool_t * pool, const char * filename, unsigned clock_rate, unsigned channel_count, unsigned samples…

2007年暑期总结

又是一个没有回家的假期&#xff0c;一个月的鸡蛋炒拉面&#xff0c;一个月沉浸在编程的世界里……收获早已超越了技术本身&#xff0c;项目的实践&#xff0c;系统的架构&#xff0c;……更多的&#xff0c;是朋友们在一起的乐趣。A5闹鬼记&#xff0c;回去洗洗就睡了&#xf…

Linux下用户组、文件权限详解=------转载文

转载自-----原文地址&#xff1a; https://www.cnblogs.com/123-/p/4189072.html Linux下用户组、文件权限详解 用户组 在linux中的每个用户必须属于一个组&#xff0c;不能独立于组外。在linux中每个文件有所有者、所在组、其它组的概念 - 所有者 - 所在组 - 其它组 - 改变用…

风暴事件处理器–每个工作者的GC日志文件

在过去的三个月中&#xff0c;我正在与一个新团队合作&#xff0c;为电信领域的大数据分析构建产品。 Storm事件处理器是我们使用的主要框架之一&#xff0c;而且确实很棒。 您可以阅读其官方文档&#xff08;已改进&#xff09;中的更多详细信息。 Storm使用Workers来完成您…

JS实现逼真的雪花飘落特效

逼真的雪花飘落特效 效果图&#xff1a; 图片素材 &#xff1a; --> ParticleSmoke.png 代码如下&#xff0c;复制即可使用&#xff1a; <!doctype html> <html> <head> <meta charset"UTF-8"> <meta name"renderer" conte…

本地执行php查看内存占用,查看页面执行php占用内存情况

今天头脑一热&#xff0c;想看一下页面在执行的过程中占用了多少内存&#xff0c;我也不知道这样做的目的是什么&#xff0c;可能是出于我的惯性思维吧。不过这样做也不是完全没用&#xff0c;你可以清楚的知道哪些页面占用的内存比较多&#xff0c;特别是对于使用共用主机的网…

阴影及定位

阴影及定位 隐藏及阴影 标签隐藏 1、显示方式 display display: none; /*表示在页面中隐藏&#xff0c;并且不占位&#xff0c;但是重新显示出来又会占位*/ 2、透明度 opacity opacity: 0; /* 0 代表完全透明 1 代表完全显示 但是即使是透明了也会在页面中占位*/ /* 显示方式透…

ABAP--关于ABAP流程处理的一些命令的说明(stop,exit,return,check,reject)

Stop 命令使用该命令的程序位置INITIALIZATION, AT SELECTION-SCREEN, START-OF-SELECTION和GET 事件中处理说明1、 当在INITIALIZATION事件执行该命令&#xff0c;系统将直接触发应用服务器和客户端屏幕元素的发送&#xff1b;2、 在其他事件中将直接触发END-OF-SELECTION事件…

[Code+#3]寻找车位

[Code#3]寻找车位 挺厉害的线段树题 m<n&#xff0c;所以n<2000,并且只有1000次修改询问&#xff0c;mqlogn的复杂度可以接受&#xff01; 求全局&#xff1f; 对行(n)建一个线段树。 线段树中维护的东西&#xff0c;一定可以包含所有“完全包含在”这个横条中的最大正方…

ActiveMQ –经纪人网络解释–第2部分

在此博客中&#xff0c;我们将看到双工网络连接器如何工作。 在上一部分中&#xff0c;我们从broker-1和broker-2创建了一个网络连接器。 我们能够看到当代理2上有一个使用者使用队列“ foo.bar”时&#xff0c;代理1上的队列“ foo.bar”的消息如何转发到代理2上的队列“ foo…

JQ实现情人节表白程序

JQ实现情人节表白页面 效果图&#xff1a; 表白利页&#xff0c;你值得拥有哦&#xff01; 代码如下&#xff0c;复制即可使用&#xff1a; <!doctype html> <html> <head> <meta charset"utf-8"> <title>JQ实现情人节表白程序<…

php 内部异步执行顺序,event_loop中不同异步操作的执行顺序

关于js的单线程、怎么创建一个异步任务都是老生常谈的话题了&#xff0c;我们今天就总结一下js不同的异步操作到底执行顺序如何。首先我们要明白js两种任务类型&#xff0c;一个是macrotask(宏任务)&#xff0c;一个是 microtask(微任务)。一个宏任务就是一个事件循环&#xff…

OpenGPU.org域名已经被劫持

这个域名被指向了上海黄浦区某地。 此时此刻&#xff0c;我的心情无比激动&#xff0c;“这年头&#xff0c;你要是不被‘墙’了&#xff0c;都不好意思出门”。 This domain name had been redirected to Shanghai, PRC. At this moment, I’m really excited that it’s my h…

Java 8日期时间API教程:LocalDateTime

该博文是Java 8中引入的有关Date Time API的系列教程的一部分。在本博文中&#xff0c;我将介绍LocalDateTime类中可用的一些方法。 LocalDateTime是一个不可更改的线程安全对象&#xff0c;它表示ISO-8601日历系统中没有时区的日期时间&#xff0c;例如2014-03-30T02&#xf…

消息队列使用的四种场景介绍(转)

消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用耦合&#xff0c;异步消息&#xff0c;流量削锋等问题 实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性架构 使用较多的消息队列有ActiveMQ&#xff0c;RabbitMQ&#xff0c;ZeroMQ&#xff0c;Ka…

一步一步SharePoint 2007之三十一:实现文档Event Handler(3)——附加Handler程序

摘要  本篇文章将介绍实现文档Event Handler的第三部分——附加Handler程序。正文  下面将记录每一步的操作过程。  1、首先打开我的网站&#xff0c;依次点击Document Center、Documents&#xff0c;进入Documents列表页面。  2、在Documents列表界面中点击Settings&a…