(十)异步-委托异步调用(4)

news2024/11/15 22:29:14

一、委托异步执行

当委托对象被调用时,它调用其调用列表中包含的方法。这是同步完成的。

如果委托对象在调用列表中只有一个方法(引用方法),它就可以异步执行这个方法。委托类有两个方法,叫作 BeginInvoke 和 EndInvoke。

  • 当调用委托的 BeginInvke 方法时,它开始在一个独立线程上执行引用方法,之后立即返回到原始线程。原始线程可以继续,而引用方法会在线程池的线程中并行执行。

  • 当程序希望获取已完成的异步方法的结果时,可以检查 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 属性,或调用委托的 EndInvoke 方法来等待委托完成。

原始线程如何知道发起的线程已经完成:

  • 在等待直到完成(wait-until-done)模式中,在发起了异步方法以及做了一些其他处理之后,原始线程就中断并且等异步方法完成之后再继续。

  • 在轮询(polling)模式中,原始线程定期检查发起的线程是否完成,如果没有则可以继续做一些其他的事情。

  • 在回调(callback)模式中,原始线程一直执行,无须等待或检查发起的线程是否完成。

在发起的线程中的引用方法完成之后,发起的线程就会调用回调方法,由回调方法在调用 EndInvoke 之前处理异步方法的结果。

原始线程是操作系统内核在创建进程时创建的第一个线程。

请添加图片描述

二、BeginInvoke 和 EndInvoke

BeginInvoke:

  • 在调用 BeginInvoke 时,参数列表中的实际参数:

    • 引用方法需要的参数;
    • 两个额外的参数—— callback 参数和 state 参数。
  • BeginInvoke 从线程池中获取一个线程并且让引用方法在新的线程中开始运行。

  • BeginInvoke 返回给调用线程一个实现 IAsyncResult 接口的对象的引用。这个接口引用包含了在线程池线程中运行的异步方法的当前状态。然后原始线程可以继续执行。

delegate long MyDel(int first,int second);//委托声明
...
static long Sun(int x,int y){ return x + y; }//方法匹配委托
...
MyDel del = new MyDel(Sum);//创建委托对象

IAsyncResult iar = del.BeignInvoke(3,5,null,null);

//IAsyncResult iar:有关新线程的信息
//del.BeignInvoke:异步调用委托
//3,5:委托参数
//callback(null) 和 state(null):额外参数

//最后一行代码的程序执行步骤:
//1、从线程池中获取一个线程并且在新的线程上运行 Sum 方法,将3和5作为实参。
//2、它收集新线程的状态信息并且把 IAsyncResult 接口的引用返回给调用线程来提供这些信息。调用线程把它保存在一个叫作 iar 的变量中。

EndInoke 方法用来获取由异步方法调用返回的值,并且释放线程使用的资源。EndInvoke 有如下的特性。

  • 它接受一个由 BeginInvoke 方法返回的 IAsyncResult 对象的引用作为参数,并找到它关联的线程。

  • 如果线程池的线程已经退出,则 EndInvoke 做如下的事情。

    • 清理退出线程的状态并释放其资源。
    • 找到引用方法返回的值并把它作为返回值返回。
  • 如果当 EndInvoke 被调用时线程池的线程仍然在运行,调用线程就会停止并等待它完成,然后再清理并返回值。因为 EndInvoke 是为开启的线程进行清理,所以必须确保对每一个 BeginInvoke 都调用 EndInvoke。

  • 如果异步方法触发了异常,则在调用 EndInvoke 时会抛出异常。

long result = del.EndInvoke(iar);
//long result:异步方法的返回值
//del:委托对象
//iar:IAsyncResult 对象

EndInvoke 提供了异步方法调用的所有输出,包括 ref 和 out 参数。如果委托的引用方法有 ref 或 out 参数,则它们必须包含在 EndInvoke 的参数列表中,并且在 IAsyncResult 对象引用之前:

long result = del.EndInvoke(out someInt,iar);
//long result:异步方法的返回值
//out someInt:Out 参数
//iar:IAsyncResult 对象

等待直到完成模式

IAsyncResult iar = del.BeginInvoke(3,5,null,null);
//在发起线程中异步执行方法的同时,
//在调用线程中处理一些其他事情
...
long result =del.EndInvoke(iar);

示例:

   delegate long MyDel(int first, int second);//声明委托类型

    class Program
    {
        static long Sum(int x,int y)
        {
            Console.WriteLine("      Inside Sum");
            return x + y;
        }

        static void Main(string[] args)
        {
            MyDel del = new MyDel(Sum);

            Console.WriteLine("Before BeginInvoke");
            IAsyncResult iar = del.BeginInvoke(3, 5, null, null);//开始异步调用
            Console.WriteLine("After BeginInvoke");

            Console.WriteLine("Doing stuff");

            long result = del.EndInvoke(iar);//等待结束并获取结果
            Console.WriteLine($"After EndInvoke:{ result }");
            Console.ReadKey();
        }
    }

输出结果:

Before BeginInvoke
After BeginInvoke
Doing stuff
Inside Sum
After EndInvoke:8

三、AsyncResult 类

BeginInvoke 返回一个 IASyncResult 接口的引用(该接口由一个 AsynResult 类型的类实现)。AsyncResult 类代表了异步方法的状态。

  • 当我们调用委托对象的 BeginInvke 方法时,系统创建了一个 AsyncResult 类对象。然而,它不返回类对象的引用,而是返回对象中包含的 IAsyncResult 接口的引用。

  • AsyncResult 对象包含一个叫作 AsyncDelegate 的属性,它返回一个指向被调用来启动异步方法的委托的引用。但是,这个属性是类对象的一部分而不是接口的一部分。

  • IsCompleted 属性返回一个布尔值,表示异步方法是否完成。

  • AsyncState 属性返回对象的一个引用,作为 BeginInvoke 方法调用时的 state 参数。它返回 object 类型引用。

请添加图片描述

四、轮询模式

在轮询模式中,原始线程发起了异步方法的调用,做一些其他处理,然后使用 IAsyncResult 对象的 IsComplete 属性来定期检查开启的线程是否完成。如果异步方法已经完成,原始线程就调用 EndInvoke 并继续。否则,它做一些其他处理,然后过一会儿再检查。

示例:

   delegate long MyDel(int first, int second);

    class Program
    {
        static long Sum(int x, int y)
        {
            Console.WriteLine("          Inside Sum");
            Thread.Sleep(100);
            return x + y;
        }

        static void Main(string[] args)
        {
            MyDel del = new MyDel(Sum);
            IAsyncResult iar = del.BeginInvoke(3, 5, null, null);//开始异步调用
            Console.WriteLine("After BeginInvoke");

            while(!iar.IsCompleted)
            {
                Console.WriteLine("Not Done");
                //继续处理
                for (long i = 0; i < 10000000; i++)
                    ;
            }

            Console.WriteLine("Done");
            long result = del.EndInvoke(iar);
            Console.WriteLine($"Result:{ result }");

            Console.ReadKey();
        }
    }

输出结果:

After BeginInvoke
Not Done
Inside Sum
Not Done
Done
Result:8

五、回调模式

一旦初始线程发起了异步方法,它就自己管自己了,不再考虑同步。当异步方法带哦用结束之后,系统调用一个用户自定义的方法(回调方法)来处理结果,并且调用委托的 EndInvoke 方法。

BeginInvoke 参数:

  • callback: 回调方法的名字(是 AsyncCallback 类型的委托)
  • state: 要传入回调方法的一个对象的引用。(任何类型的对象)

1、回调方法

void AsyncCallback(IAsyncResult iar)

使用回调方法

IAsyncResult iar1 = del.BeginInvoke(3,5,new AsyncCallback(CallWhenDone),null);
IAsyncResult iar2 = del.BeginInvoke(3,5,new CallWhenDone,null);
//

2、在回调方法内调用 EndInvoke

如果不将 BeginInvoke 的 state 参数用于其他目的,可以使用它给回调方法发送委托的引用:

IAsyncResult IAR = del.BeginInvoke(3,5,CallWhenDone,del);
//del:委托对象
//第二个del:把委托对象作为状态参数发送

可以从作为参数发送给方法的 IAsyncResult 对象中提取出委托的引用。

void CallWhenDone(IAsyncResult iar)
{
AsyncResult ar = (AsyncResult) iar;//获取类对象的引用
MyDel del = (MyDel)ar.AsyncDelegate;//获取委托的引用

long Sum = del.EndInvoke(iar);//调用EndInvoke
...
}

请添加图片描述

使用回调模式的示例:

    delegate long MyDel(int first, int second);

    class Program
    {
        static long Sum(int x, int y)
        {
            Console.WriteLine("          Inside Sum");
            Thread.Sleep(100);
            return x + y;
        }

        static void CallWhenDone(IAsyncResult iar)
        {
            Console.WriteLine("              Inside CallWhenDone.");
            AsyncResult ar = (AsyncResult)iar;
            MyDel del = (MyDel)ar.AsyncDelegate;

            long result = del.EndInvoke(iar);
            Console.WriteLine("               The result is : {0}.", result);
        }

        static void Main(string[] args)
        {
            MyDel del = new MyDel(Sum);

            Console.WriteLine("Before BeginInvoke");
            IAsyncResult iar = del.BeginInvoke(3, 5, new AsyncCallback(CallWhenDone), null);

            Console.WriteLine("Doning more work in Main.");
            Thread.Sleep(500);
            Console.WriteLine("Done with Main. Exiting.");
            Console.ReadKey();
        }
    }

输出结果:

Before BeginInvoke
Inside Sum
Doning more work in Main.
Inside CallWhenDone.
The result is : 8.
Done with Main. Exiting.

六、计时器

一种定期重复运行异步方法的方法。

  • 计时器在每次到期之后调用回调方法。
void TimerCallback(object state)
  • 当计时器到期之后,系统会在线程池中的一个线程上设置回调方法。
  • 可以设置的计时器的特性:
    • dueTime: 回调方法首次被调用之前的时间。如果 dueTime 被设置为特殊的值 Timeout.Infinite,则计时器不会开始;如果被设置为0,则回调函数被立即调用。
    • period: 两次成功调用回调函数之间的时间间隔。如果它的值被设置为 Timeout.Infinite,则回调在首次被调用之后不会再被调用。
    • state: 可以是 null 或在每次回调方法执行时要传入的对象的引用。
Timer(TimerCallback callback, object state, uint dueTime, uint period)

如果创建了 Timer 对象的实例:

Timer myTimer = new Timer(MyCallback, someObject, 2000, 1000);
//MyCallback:回调的名字
//someObject:传给回调的对象
//2000:在2000毫秒后第一次调用
//1000:每1000 毫秒调用一次

示例:

  class Program
    {
        int TimmesCalled = 0;
        void Display(object state)
        {
            Console.WriteLine($"{ (string)state } {  ++TimmesCalled }");
        }
        static void Main(string[] args)
        {
            Program p = new Program();

            Timer myTimer = new Timer(p.Display, "Processing timer event", 2000, 1000);
            Console.WriteLine("Timer started.");
            Console.ReadLine();
            Console.ReadKey();
        }
    }

书上说大概5秒后会终止输出结果,但是我的编程环境里,并不会这样,会一直不停地输出。代码例子和书上的一模一样的。按理说,这并不会结束地呼出结果,才是对的吧?先不管了,以后遇到了这个情况再看看。

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

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

相关文章

【计算机网络】进程崩溃或网络中断后,TCP 连接还存在吗?

【计算机网络】进程崩溃或网络中断后&#xff0c;TCP 连接还存在吗&#xff1f; 参考资料&#xff1a; TCP 连接&#xff0c;一端断电和进程崩溃有什么区别&#xff1f; 拔掉网线后&#xff0c; 原本的 TCP 连接还存在吗&#xff1f; TCP/IP卷一:94—TCP保活机制 TCP Keepaliv…

记一次gitlab应急响应

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 事件背景介绍02 事件分析过程03 事件分析结果04 安全加固建议 01 事件背景介绍 某内部应急演练中&#xff0c;态势感知平台上出现gitlab RCE漏洞攻击成功告警&#xff0c;现需根据流量情况进行安全…

013、数据库管理之连接管理

连接管理 TiDB的连接特性连接TiDB 数据库开发接口支持 实验案例 TiDB的连接特性 无状态MySQL协议支持 100% 兼容MySQL 5.7协议支持MySQL 5.7常用功能与语法 MySQL 语法支持的限制&#xff08;不支持的功能特性&#xff09; 存储过程触发器外键函数其它 连接TiDB 数据库 使…

记一次shiro应急响应

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 事件背景介绍02 事件分析过程03 事件分析结果04 安全加固建议 01 事件背景介绍 某内部应急演练中&#xff0c;安全部门监测到WAF上存在shiro攻击成功告警信息&#xff0c;现需根据流量情况进行安全…

Vue中的表单上传与文件预览

Vue中的表单上传与文件预览 在Web应用程序中&#xff0c;文件上传和预览是非常常见的功能。在Vue中&#xff0c;我们可以使用axios和FormData来实现表单上传&#xff0c;使用FileReader来实现文件预览。在本文中&#xff0c;我们将介绍如何在Vue中实现表单上传和文件预览功能。…

[阿里云使用k8s技术部署微服务]

1.1 检查CPU/内存/网络设置 对虚拟机的要求(必须): CPU:最少2核 内存:master >4G&#xff0c;node >3G 网络:NAT模式 操作系统版本: Docker 要求 CentOS 系统的内核版本必须高于 3.10。 如果内核版本为3.10&#xff0c;则发行编号最好能升级到1127&#xff0c; 即:3.10.0…

1000*B. Keep it Beautiful

input 3 9 3 7 7 9 2 4 6 3 4 5 1 1 1 1 1 5 3 2 1 2 3output 111110010 11111 11011 解析&#xff1a; 如果数据不小于前一个数据&#xff0c;则一直为美丽序列&#xff1b; 当碰到第一个小于末尾的数据时&#xff0c;1. 如果他比首数据大&#xff0c;则不符题意。2. 小于等…

【ARMv8 SIMD和浮点指令编程】NEON 移动指令——精通 MOV?

移动指令主要涉及 MOV 和 MVN&#xff0c;它们分别是移动和求反移动。如果你认为仅仅两条指令&#xff0c;还是太小看设计者了&#xff01; 1 MOV (element) 将向量元素移动到另一个向量元素。该指令将源 SIMD&FP 寄存器的向量元素复制到目标 SIMD&FP 寄存器的指定向…

短视频seo系统源码私有化部署分享

短视频seo矩阵系统源码部署需要以下步骤&#xff1a; 确定系统环境要求&#xff1a;账号矩阵系统需要服务器环境支持PHP和MySQL数据库&#xff0c;因此需要确保服务器环境符合要求&#xff0c;并安装好相应的软件。例如&#xff0c;可以使用XAMPP或WAMP等软件包来快速安装PHP和…

中国唯一 一家Linux 基金会金牌会员 落户阿里云

导读2 月 20 日&#xff0c;全球知名非营利性组织 Linux 基金会宣布&#xff0c;阿里云正式成为 Linux 基金会金牌会员。阿里云表示将持续加大对开源项目的支持&#xff0c;并发挥自己的力量。 2 月 20 日&#xff0c;全球知名非营利性组织 Linux 基金会宣布&#xff0c;阿里云…

pyqt6安装

1、安装pyqt6和pyqt6-tools包 注意&#xff1a;pyqt6-tools目前仅支持python3.9版本&#xff0c;3.9版本后的安装部成功。&#xff08;截止2022.11.20&#xff09; 1.1 安装pyqt6和pyqt6-tools 安装pyqt和pyqt6-tools可以使用conda和pip进行安装 &#xff08;1&#xff09;…

【备战秋招】每日一题:2023.05-B卷-华为OD机试 - 报文回路

为了更好的阅读体检&#xff0c;可以查看我的算法学习博客报文回路 输入描述 第一行抓到的报文数量&#xff0c;后续C行依次输入设备节点D1和D2&#xff0c;表示从D1到D2发送了单向的报文&#xff0c;D1和D2用空格隔开 输出描述 组播通路是否“正常”&#xff0c;正常输出T…

SQL语言的四大组成部分——DCL(数据控制语言)

1️⃣前言 SQL语言中的DCL&#xff08;Data Control Language&#xff09;是一组用于控制数据库用户访问权限的语言&#xff0c;主要包括GRANT、REVOKE、DENY等关键字。 文章目录 1️⃣前言2️⃣DCL语言3️⃣GRANT关键字4️⃣REVOKE关键字5️⃣DENY关键字6️⃣总结附&#xff1…

从零搭建完整python自动化测试框架(UI自动化和接口自动化 )——持续更新

一、总体框架 总体框架如下图&#xff1a; 用例扫描、测试结果反馈&#xff0c;如要和其它项目管理系统或是用例管理系统对接&#xff08;比如testlink&#xff09;&#xff0c;就需要单独出来进行处理。 对于大型的产品&#xff0c;用例数特别多的话&#xff0c;需要建设一个…

AIGC提示(prompt)工程之开宗明义篇

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

VMware公司成为Linux基金会金牌会员

导读VMware是云基础架构和企业移动性的全球领导者&#xff0c;多年来一直积极参与开源开发。VMware通过Linux基金会项目(如ONAP&#xff0c;Cloud Native Computing Foundation(CNCF)&#xff0c;Cloud Foundry&#xff0c;Open vSwitch等)稳步提高其开源参与度。它刚刚成为了金…

HDFS初认识

HDFS初认识 文章目录 HDFS初认识HDFS是什么&#xff1f;HDFS的假想和设计目标HDFS的优缺点优点缺点 HDFS的架构组成客户端NameNodeDataNodeSecondary NameNode职责checkpoint机制 参考 HDFS是什么&#xff1f; Hadoop分布式文件系统&#xff08;HDFS&#xff09;是一个分布式文…

Websocket+protobuf怎么与服务器通信

Websocketprotobuf怎么与服务器通信 Websocket&#xff1a;WebSocket是⼀种⽹络传输协议&#xff0c;可在单个TCP连接上进⾏双全⼯通信&#xff0c;位于OSI模型的 应⽤层 实现⼀个简单的客⼾端和服务端 安装websockets pip3 install websockets客户端代码 import asyncio …

记一次异常外联事件应急响应

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 事件背景介绍02 事件分析过程03 事件分析结果04 安全加固建议 01 事件背景介绍 某内部应急演练中&#xff0c;安全部门收到来自业务部门的告警&#xff0c;称应用服务器存在异常外联情况&#xff0…

管理类联考——英语二——技巧篇——阅读理解——taiqi

第一章 翻译技巧概述 一、词汇方面 (一&#xff09;词义选择 大多数英语词汇是多义的&#xff0c;翻译时必须选择正确的词义。词义选择的方法有三&#xff1a;根据上下文和词的搭配选择根据词类选择、根据专业选择。 (二&#xff09;词义转换 在理解英文词汇的原始意义基础…