C# 创建线程的多种方式之异步调用基础知识

Wesley13
• 阅读 428

创建线程一种简单的方式是委托的异步调用,Delegate类提供了BeginInvoke方法,该方法可以传递委托类型定义的参数(所以BeginInvoke参数数量是可变的),另外还有2个固定的参数 回调函数委托AsynsCallBack和类型Object(如果不使用可直接赋值为null)。

BeginInvoke() 的返回值为IAsynResult,通过它的IsComplete属性可以判断异步调用是否完成。

static void Main(string[] args)
        {
            Func<int, int> act1 = new Func<int, int>(Calculate);
            Console.WriteLine("Main Start....");
            IAsyncResult ar = act1.BeginInvoke(20,null, null);
            while (!ar.IsCompleted)
            {
                Console.WriteLine("Main is waiting");
                Thread.Sleep(500);
            }
            int result = act1.EndInvoke(ar);
            Console.WriteLine("Result is " + result);
            Console.ReadLine();
        }

        private static int Calculate(int total)
        {
            int sum = 0;
            for (int i = 0; i < total;i++ )
            {
                sum += i;
                Thread.Sleep(100);
            }
            return sum;
        }

运行返回结果:

Main Start....
Main is waiting
Main is waiting
Main is waiting
Main is waiting
Main is waiting
Result is 190

事实上,EndInvoke也是会等到异步调用结束,返回结果的。此外,IAsynResult的AsyncWaitHandle属性是WaitHandle类型,利用WaitOne()能够达到上述同样的效果,我觉得有一个好处就是可以利用WaitAll()等待多个异步调用同时完成:

static void Main(string[] args)
        {
            Func<int, int> act1 = new Func<int, int>(Calculate);
            Func<int, int> act2 = new Func<int, int>(Calculate);
            Console.WriteLine("Main Start....");
            IAsyncResult ar1 = act1.BeginInvoke(20,null, null);
            IAsyncResult ar2 = act2.BeginInvoke(30, null, null);
            if(WaitHandle.WaitAll(new WaitHandle[]{ar1.AsyncWaitHandle,ar2.AsyncWaitHandle},5000))
            {
                Console.WriteLine("Waiting is over");
                
            }
            int result1 = act1.EndInvoke(ar1);
            int result2 = act2.EndInvoke(ar2);
            Console.WriteLine("Result1 is {0},Result2 is {1}", result1, result2);
            Console.ReadLine();
        }

        private static int Calculate(int total)
        {
            int sum = 0;
            for (int i = 0; i < total;i++ )
            {
                sum += i;
                Thread.Sleep(100);
            }
            return sum;
        }

我声明了act1和act2两个委托对象,并同时进行异步调用,WaitHandle.WaitAll(new WaitHandle[]{ar1.AsyncWaitHandle,ar2.AsyncWaitHandle},5000) 等待同时完成,最后返回结果:

Main Start....
Waiting is over
Result1 is 190,Result2 is 435

 除了以上2种方式返回运行结果,还可以使用AsynsCallBack回调,BeginInvoke()的最后一个参数可以用ar.Asynstate访问,以便在回调函数中使用,例如传递委托实例获取运行结果:

static void Main(string[] args)
        {
            Func<int, int> act1 = new Func<int, int>(Calculate);
            Console.WriteLine("Main Start....");
            IAsyncResult ar1 = act1.BeginInvoke(20, new AsyncCallback(CalculateComplete), act1);
            while(!ar1.IsCompleted){
                Console.WriteLine("Main is waiting");
                Thread.Sleep(500);
            }
            Console.ReadLine();
        }

        private static int Calculate(int total)
        {
            int sum = 0;
            for (int i = 0; i < total;i++ )
            {
                sum += i;
                Thread.Sleep(100);
            }
            return sum;
        }

        private static void CalculateComplete(IAsyncResult ar)
        {
            Console.WriteLine("Counting is over...........");
            Func<int, int> act = ar.AsyncState as Func<int, int>;
            Console.WriteLine("Result is "+act.EndInvoke(ar));
        }

运行结果:

Main Start....
Main is waiting
Main is waiting
Main is waiting
Main is waiting
Main is waiting
Counting is over...........
Result is 190

回调函数是在委托线程中完成的,还可以使用Lamda表达式,更加简便,传入最后一个参数,因为Lamda表达式可以访问域外变量:

static void Main(string[] args)
        {
            Func<int, int> act1 = new Func<int, int>(Calculate);
            Console.WriteLine("Main Start....");
            IAsyncResult ar1 = act1.BeginInvoke(20, ar => { Console.WriteLine("Result is " + act1.EndInvoke(ar)); }, null);
            while(!ar1.IsCompleted){
                Console.WriteLine("Main is waiting");
                Thread.Sleep(500);
            }
            Console.ReadLine();
        }
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
28、可变参数和集合数组的互转
可变参数在定义方法的时候不确定该定义多少个参数时,可以使用可变参数来定义,这样方法的参数个数会根据调用者来确定。注意:如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个。格式:修饰符返回值类型方法名(数据类型…变量名){}例:publicclasslist_test
Easter79 Easter79
2年前
Typescript 常见的几种函数重载方法详解与应用示例
所谓的重载,其实就是使用相同的函数名,传入不同数量的参数或不同类型的参数,以此创建出多个方法或产生不同结果。1\.最常见的,也就是根据定义傻瓜式地判断参数类型与数量functionshowPerson(name,...others){console.log(name,others)}
Wesley13 Wesley13
2年前
mysql中时间比较的实现
MySql中时间比较的实现unix\_timestamp()unix\_timestamp函数可以接受一个参数,也可以不使用参数。它的返回值是一个无符号的整数。不使用参数,它返回自1970年1月1日0时0分0秒到现在所经过的秒数,如果使用参数,参数的类型为时间类型或者时间类型的字符串表示,则是从1970010100:00:0
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
5.4 异步TCP编程(二)
    5.4.2异步TCP应用编程的一般方法(本节可以忽略)  使用异步TCP编程时,除了套接字有对应的异步操作方式外,_TcpListener_和_TcpClient_类均提供了返回结果为_IAsyncResult_类型的异步操作的方法。    1、BeginAcceptTcpClient方法和EndAcceptTcpClien
Stella981 Stella981
2年前
Multithreading
1.使用线程的理由2.基本知识3.线程的使用4.线程同步4.线程池5.Task类6.委托异步执行7.线程同步1.使用线程的理由可以
Wesley13 Wesley13
2年前
5.4 异步TCP编程(三)
5.4.3使用异步方式调用同步方法  .NETFramework提供了一种可以利用委托异步调用任何方法的技术,唯一的要求就是需要声明一个与要调用的方法具有相同签名的委托。对于任何一个方法,如果希望异步执行,最简单的方法就是通过调用委托的BeginInvoke方法开始异步执行,然后执行其他操作,最后调用委托的EndInvoke方法结束异步
小万哥 小万哥
2个月前
Java 构造函数与修饰符详解:初始化对象与控制权限
Java构造函数Java构造函数是一种特殊的类方法,用于在创建对象时初始化对象的属性。它与类名相同,并且没有返回值类型。构造函数的作用:为对象的属性设置初始值执行必要的初始化操作提供创建对象的多种方式构造函数的类型:默认构造函数:无参数的构造函数,如果用户