委托和方法的异步调用

news2024/12/26 3:05:29

概述        

        异步调用,通常情况下用于执行一些耗时的操作,同时能够保证当前主线程在执行异步调用之后依然能够继续向下执行。异步执行时,系统往往会创建一个新的线程,但需注意,当每一个异步执行都需要创建线程时,往往会对性能有影响。因此,使用线程池能够有效处理这一问题,避免了进行异步调用时创建、销毁线程的开销。

        本片文章,结合委托和异步来对BeginInvoke()方法、EndInvoke()方法和其相关的IAsyncResult做一个简单的学习。

示例一:不使用异步调用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    
    internal class Program
    {        
        static void Main(string[] args)
        {
            Console.WriteLine("Client application started!\n");
            Console.WriteLine(DateTime.Now.ToString());
            Thread.CurrentThread.Name = "Main Thread";
            Calculator cal = new Calculator();
            int result = cal.Add(2, 5);
            Console.WriteLine("Result: {0}\n", result);

            // 做某些其他的事情,模拟需要执行3秒钟
            for (int i = 1; i <= 3; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(i));
                Console.WriteLine("{0}: Client executed {1} second(s).",
                        Thread.CurrentThread.Name, i);
            }
            Console.WriteLine(DateTime.Now.ToString());
            Console.WriteLine("\nPress any key to exit...");
            Console.ReadKey();

        }

    }
    public class Calculator
    {
        public int Add(int x, int y)
        {
            //判断执行当前代码的线程是否为线程池中的线程
            if (Thread.CurrentThread.IsThreadPoolThread)
            {
                Thread.CurrentThread.Name = "Pool Thread";
            }
            Console.WriteLine("Method invoked!");

            // 执行某些事情,模拟需要执行2秒钟
            for (int i = 1; i <= 2; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(i));
                Console.WriteLine("{0}: Add executed {1} second(s).",
                        Thread.CurrentThread.Name, i);
            }
            Console.WriteLine("Method complete!");
            return x + y;
        }
    }
}

        由上图可知,在不使用异步执行时,主线程大概执行了6秒左右,因为线程是串行执行的

        接下来,定义一个委托 ,并使用BeginInvoke()方法来异步调用它

示例二:BeginInvoke()方法调用

1. 先看代码示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    //声明委托
    public delegate int AddDelegate(int x, int y);
    internal class Program
    {        
        static void Main(string[] args)
        {
            Console.WriteLine("Client application started!\n");
            Console.WriteLine(DateTime.Now.ToString());
            Thread.CurrentThread.Name = "Main Thread";
            Calculator cal = new Calculator();

            AddDelegate del=new AddDelegate(cal.Add);
            IAsyncResult result=del.BeginInvoke(3,4,null,null);

            // 做某些其他的事情,模拟需要执行3秒钟
            for (int i = 1; i <= 3; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(i));
                Console.WriteLine("{0}: Client executed {1} second(s).",
                        Thread.CurrentThread.Name, i);
            }
            Console.WriteLine(DateTime.Now.ToString());
            Console.WriteLine("\nPress any key to exit...");
            Console.ReadKey();

        }

    }
    public class Calculator
    {
        public int Add(int x, int y)
        {
            //判断执行当前代码的线程是否为线程池中的线程
            if (Thread.CurrentThread.IsThreadPoolThread)
            {
                Thread.CurrentThread.Name = "Pool Thread";
            }
            Console.WriteLine("Method invoked!");

            // 执行某些事情,模拟需要执行2秒钟
            for (int i = 1; i <= 2; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(i));
                Console.WriteLine("{0}: Add executed {1} second(s).",
                        Thread.CurrentThread.Name, i);
            }
            Console.WriteLine("Method complete!");
            return x + y;
        }
    }
}

 

①BeginInvoke()方法参数

        BeginInvoke()除了最后两个参数为AsyncCallback类型和Object类型以外,前面的参数类型和个数与委托定义相同

        AsyncCallback参数

                AsyncCallback是一个委托类型,它用于方法的回调,也就是说当异步方法执行完毕时自动进行调用的方法

        Object类型参数

                Object类型用于传递任何想要的数据类型,它可以通过IAsyncResult的AsyncState属性获得

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    //声明委托
    public delegate int AddDelegate(int x, int y);
    internal class Program
    {        
        static void Main(string[] args)
        {
            Console.WriteLine("Client application started!\n");
            Console.WriteLine(DateTime.Now.ToString());
            Thread.CurrentThread.Name = "Main Thread";
            Calculator cal = new Calculator();

            AddDelegate del=new AddDelegate(cal.Add);
            AsyncCallback async = new AsyncCallback(OnAddComplete);
            string data = "在OnAddComplete()方法中获得了调用BeginInvoke()时最后一个参数传递的值";

            IAsyncResult result=del.BeginInvoke(3,4,async,data);
            

            // 做某些其他的事情,模拟需要执行3秒钟
            for (int i = 1; i <= 3; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(i));
                Console.WriteLine("{0}: Client executed {1} second(s).",
                        Thread.CurrentThread.Name, i);
            }
            
            Console.WriteLine(DateTime.Now.ToString());
            Console.WriteLine("\nPress any key to exit...");
            Console.ReadKey();

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="asyncResult">在调用BeginInvoke()后不再需要保存IAsyncResult了,因为AsyncCallback委托将该对象定义在了回调方法的参数列表中;</param>
        static void OnAddComplete(IAsyncResult asyncResult)
        {
            AsyncResult result = (AsyncResult)asyncResult;
            AddDelegate del = (AddDelegate)result.AsyncDelegate;
            string data = (string)asyncResult.AsyncState;

            int rtn = del.EndInvoke(asyncResult);
            Console.WriteLine("{0}: Result, {1}; Data: {2}\n",
                    Thread.CurrentThread.Name, rtn, data);
        }
    }
    public class Calculator
    {
        public int Add(int x, int y)
        {
            //判断执行当前代码的线程是否为线程池中的线程
            if (Thread.CurrentThread.IsThreadPoolThread)
            {
                Thread.CurrentThread.Name = "Pool Thread";
            }
            Console.WriteLine("Method invoked!");

            // 执行某些事情,模拟需要执行2秒钟
            for (int i = 1; i <= 2; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(i));
                Console.WriteLine("{0}: Add executed {1} second(s).",
                        Thread.CurrentThread.Name, i);
            }
            Console.WriteLine("Method complete!");
            return x + y;
        }
    }
}

 

 

②BeginInvoke()方法结果返回类型

        BeginInvoke()方法返回了一个实现了IAsyncResult接口的对象

        AsyncResult的用途有这么几个:传递参数,它包含了对调用了BeginInvoke()的委托的引用;它还包含了BeginInvoke()的最后一个Object类型的参数;它可以鉴别出是哪个方法的哪一次调用,因为通过同一个委托变量可以对同一个方法调用多次

③EndInvoke()方法

        EndInvoke()方法接受IAsyncResult类型的对象,所以在调用BeginInvoke()之后,需要保留IAsyncResult,以便在调用EndInvoke()时进行传递。这里最重要的就是EndInvoke()方法的返回值,它就是方法的返回值。除此以外,当客户端调用EndInvoke()时,如果异步调用的方法没有执行完毕,则会中断当前线程而去等待该方法,只有当异步方法执行完毕后才会继续执行后面的代码。所以在调用完BeginInvoke()后立即执行EndInvoke()是没有任何意义的。我们通常在尽可能早的时候调用BeginInvoke(),然后在需要方法的返回值的时候再去调用EndInvoke() ,或者根据情况在晚些时候调用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    //声明委托
    public delegate int AddDelegate(int x, int y);
    internal class Program
    {        
        static void Main(string[] args)
        {
            Console.WriteLine("Client application started!\n");
            Console.WriteLine(DateTime.Now.ToString());
            Thread.CurrentThread.Name = "Main Thread";
            Calculator cal = new Calculator();

            AddDelegate del=new AddDelegate(cal.Add);
            IAsyncResult result=del.BeginInvoke(3,4,null,null);

            // 做某些其他的事情,模拟需要执行3秒钟
            for (int i = 1; i <= 3; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(i));
                Console.WriteLine("{0}: Client executed {1} second(s).",
                        Thread.CurrentThread.Name, i);
            }

            var rtn=del.EndInvoke(result);
            Console.WriteLine("获取结果:{0}\n", rtn);
            Console.WriteLine(DateTime.Now.ToString());
            Console.WriteLine("\nPress any key to exit...");
            Console.ReadKey();

        }

    }
    public class Calculator
    {
        public int Add(int x, int y)
        {
            //判断执行当前代码的线程是否为线程池中的线程
            if (Thread.CurrentThread.IsThreadPoolThread)
            {
                Thread.CurrentThread.Name = "Pool Thread";
            }
            Console.WriteLine("Method invoked!");

            // 执行某些事情,模拟需要执行2秒钟
            for (int i = 1; i <= 2; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(i));
                Console.WriteLine("{0}: Add executed {1} second(s).",
                        Thread.CurrentThread.Name, i);
            }
            Console.WriteLine("Method complete!");
            return x + y;
        }
    }
}

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

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

相关文章

【校招VIP】java语言考点之synchronized和volatile

考点介绍&#xff1a; synchronized和volatile两个关键字也是校招常考点之一。volatile可以禁止进行指令重排。synchronized可作用于一段代码或方法&#xff0c;既可以保证可见性&#xff0c;又能够保证原子性...... 『java语言考点之synchronized和volatile』相关题目及解析…

C语言:指针数组

一、指针数组介绍 指针数组本质是数组&#xff0c;是一个存放指针的数组 代码如下&#xff1a; arr1和arr2就是指针数组 int main() {int a 1; int *pa &a;int b 2; int *pb &b;int c 3; int *pc &c;int d 4; int *pd &d;int e 5; int *pe &e;in…

【pyqt5界面化工具开发-12】QtDesigner图形化界面设计

目录 0x00 前言 一、启动程序 二、基础的使用 三、保存布局文件 四、加载UI文件 0x00 前言 关于QtDesigner工具的配置等步骤&#xff08;网上链接也比较多&#xff09; 下列链接非本人的&#xff08;如果使用pip 在命令行安装过pyqt5以及tools&#xff0c;那么就可以跳过…

Ansible学习笔记5

copy模块&#xff1a;&#xff08;重点&#xff09; copy模块用于对文件的远程拷贝&#xff08;如把本地的文件拷贝到远程主机上。&#xff09; 在master的主机上准备一个文件&#xff0c;拷贝文件到group1的所有主机上。 这个用的频率非常高&#xff0c;非常有用的一个模块…

28 - restful -request和response

response: 需要定制返回字段的格式 request: 需要校验前端传来的参数 代码示例: 1. 创建模型类 from datetime import datetime from ext import dbclass User(db.Model):id db.Column(db.Integer, primary_keyTrue, autoincrementTrue)username db.Colu…

Error:java: OutOfMemoryError: insufficient memory

现象&#xff1a;idea编译代码&#xff08;Build&#xff09;报错&#xff1a;Error:java: OutOfMemoryError: insufficient memory 亲测有效 在进行代码编译的时候出现以上的提示。从中可以看是内存方面的问题。只需要调节IDEA在编译过程中&#xff0c;内存大小的设置&#…

面向对象的设计原则

设计模式 Python 设计模式&#xff1a;对软件设计中普遍存在&#xff08;反复出现&#xff09;的各种问题&#xff0c;所提出的解决方案。每一个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计 面向对象 三大特性&#xff1a;封装、继承、多态 …

代码随想录笔记--哈希表篇

目录 1--有效的字母异位词 2--两个数组的交集 3--两数之和 4--四数相加II 5--三数之和 6--四数之和 1--有效的字母异位词 利用哈希表存储每个字母的出现次数&#xff0c;比较两个字符串各个字母出现次数是否相等即可&#xff1b; #include <iostream> #include <…

常用的css样式

1&#xff1a;flex布局 .flex-between {display: flex;justify-content: space-between; }.flex-evenly {display: flex;justify-content: space-evenly; }.flex-end {display: flex;justify-content: flex-end; }.flex {display: flex; }.flex-center {display: flex;justify…

实验室的服务器和本地pycharm怎么做图传

参考 远程调试 qt.qpa.xcb: could not connect to display, echo DISPLAY为空[已解决]_功夫小象的博客-CSDN博客 先安装x11 MobaXterm x11-forwarding_C--G的博客-CSDN博客 我是在容器中搞得 1&#xff0c;安装qt5 pip install PyQt5 -i https://pypi.douban.com/simple …

vue 入门案例模版

vue 入门案例1 01.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> &l…

科创板50ETF期权交易:详细规则、费用、保证金和开户攻略

科创板50ETF期权是指以科创板50ETF为标的资产的期权合约。科创板50ETF是由交易所推出的一种交易型开放式指数基金&#xff08;ETF&#xff09;&#xff0c;旨在跟踪科创板50指数的表现&#xff0c;下文介绍科创板50ETF期权交易&#xff1a;详细规则、费用、保证金和开户攻略&am…

如何解决vue3.0+typescript项目提示找不到模块“./App.vue

一、解决方案如下&#xff1a;需在项目目录下加上下面这段代码即可&#xff01;如果没有vite-env.d.ts目录需要继续往下看 declare module *.vue {import type { DefineComponent } from vueconst vueComponent: DefineComponent<{}, {}, any>export default vueCompon…

云服务器利用Docker搭建sqli-labs靶场环境

一、安装宝塔面板 使用xshell、electerm、SecureCRT等远程终端连接登陆上云服务器&#xff0c;在Linux宝塔面板使用脚本安装 安装后&#xff0c;如下图&#xff1a;按照提示&#xff0c;在云服务器防火墙/安全组放行Linux宝塔面板的端口 在浏览器打开上述网址&#xff0c;登…

创建一个空的vue项目,配置及步骤

查看需要的环境及插件版本 创建vue命令 默认配置 手动配置 其他 hash和history的区别&#xff1a; hash 模式&#xff0c;url后&#xff0c;会带着#&#xff0c;改变hash&#xff0c;页面不会刷新&#xff0c;不会更改整个页面&#xff0c;只会更改#后面路由配置的内容&#x…

自定义overflow轨道样式,并且滚动条两边存在间距(滚动条不贴边显示)

最终效果 实现思路 border box-shadow 实现代码 ::-webkit-scrollbar {width: 20px;height: 4px; }::-webkit-scrollbar-thumb {border-radius: 20px;border: 6px solid rgba(0, 0, 0, 0);box-shadow: 14px 0px 0 #e3e3e3 inset; }::-webkit-scrollbar-thumb:hover {box-sh…

水经微图网页版界面功能说明

水经微图网页版&#xff0c;可轻松将关注的地点制作成您的个人地图。 您可以在任意位置添加标注点或绘制地图&#xff0c;查找地点并将其保存到您的地图中&#xff0c;或导入地图数据迅速制作地图并保存&#xff0c;您还可以运用图标和颜色展示个性风采&#xff0c;从而可让每…

低温控制中自增压液氮罐改进为杜瓦电热压力精密调节的解决方案

摘要&#xff1a;在液氮低温冷却控制系统中&#xff0c;目前大多数都采用自增压液氮罐作为低温源&#xff0c;但存在的问题是罐内压力无法精密调节、喷射液氮温度和流量不稳定、冷却温度无法准确控制以及冷却温度范围较窄等问题。为此本文提出了液氮罐内电加热压力调节解决方案…

Jupyter installation Tutorial

文章目录 1. 面向的系统2. 什么是Jupyter&#xff1f;3. 安装Python环境4. 安装Jupyter notebook5. Jupyter的启动和配置6. Jupyter的使用技巧7. conclusion参考文献 1. 面向的系统 Windows安装 2. 什么是Jupyter&#xff1f; Jupyter Notebook是一个开源的Web应用程序&…

如何优化vue项目 如何提升速度

优化 Vue 项目和提升速度可以从多个方面入手。下面是一些常见的优化技巧&#xff1a; 使用生产环境构建&#xff1a;在部署项目时&#xff0c;使用 Vue 的生产环境构建可以去除开发环境的调试工具和警告信息&#xff0c;减小项目的体积。 代码拆分和懒加载&#xff1a;将项目代…