我上次写创建线程的时候就想写一篇深入异步调用的笔记,但是由于当时对windows的进程与线程的概念不太清楚,没敢写,今天我仔细的分析并调试了一下C#中的异步调用的四种方法。把学习笔记分享出来。
假如要在一个线程中异步执行一个方法,则先创建一个该方法的委托类型,然后CLR会自动为该委托类型定义一个BeginInvoke方法和EndInvoke方法,我们就靠这两个方法异步调用委托类型指向的方法(这句话有点绕口,呵呵)
BeginInvoke这个方法用于启动异步调用,该方法具有和要异步执行的方法具有相同的参数列表,只不过又多加了两个参数,多加的那两个参数的作用在后面介绍。执行BeginInvoke方法后,将立即返回一个IAsyncResult,用于监视被调用方法执行的进度。
EndInvoke这个方法用于得到异步调用的结果,调用BeginInvoke方法后随时可以调用EndInvoke方法,假如异步调用还没有完成,EndInvoke会阻塞到异步调用执行完毕,EndInvoke的参数包括被调用方法的out和ref参数,还有在调用BeginInvoke方法时得到的那个IAsyncResult(好像就是一个哈希表的key,可以靠这个key去得到相应的线程,这样就可以处理多线程而不至于混乱了)
第一种方法:使用BeginInvoke方法后,主线程去执行一些操作,然后再使用EndInvoke方法等待被调用方法完成,以下是示例代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace sample
{
    class AsyncDemo  // 我定义了一个演示的类,里面有一个测试方法TestMethod 其实完全可以把这个TestMethod写到Main()函数的同一个类中,只不过写成static方法即可
    {
        public string TestMethod(int callDuration, out int threadid)
        {
            Console.WriteLine("Test Method begins");
            Thread.Sleep(callDuration);//睡眠callDuration指定的毫秒
            threadid = AppDomain.GetCurrentThreadId();//获取当前线程的id
            return "MyCallTime was" + callDuration.ToString();//返回当前线程睡眠的时间

        }
    }
    public delegate string AsyncDelegate(int callDuration, out int threadid); //创建一个AsyncDemo类中TestMethod方法相同签名的委托类型
    class Program
    {
        static void Main(string[] args)
        {
            int threadID;
            AsyncDemo ad = new AsyncDemo();//声明一个AsyncDemo类型的对象ad,并创建一个实例赋给它
            AsyncDelegate andl = new AsyncDelegate(ad.TestMethod);//声明一个AsyncDelegate类型的对象andl,并让他指向ad对象的TestMethod方法
            IAsyncResult ar = andl.BeginInvoke(3000, out threadID, null, null);//执行andl的BeginInvoke方法,返回一个IAsyncResult类型的实例对象给ar变量,其实是一个号码牌(不知道这样说是否形象)
            Thread.Sleep(10);//使当前线程睡眠10毫秒(其实可去掉这句,我写这个的目的是确保异步线程已启动,再执行以下语句)
            Console.WriteLine("Main Thread {0} Does Some Work",
                AppDomain.GetCurrentThreadId());//输出当前线程的id
            string ret = andl.EndInvoke(out threadID, ar);//使用EndInvoke方法,传入out或ref类型参数和在调用BeginInvoke方法时得到的IAsyncResult,此时主线程将等待异步调用执行完毕,返回结果后执行以下语句
            Console.WriteLine("The call executed on thread {0},with return value : {1}",
                threadID, ret);
            Console.ReadLine();
        }
    }
}
 
ok,以上是第一种直接使用EndInvoke来等待异步调用完成的方法

C#异步调用使用IAsyncResult的WaitHandle属性的WaitOne()方法来实现多线程同步 (二)

第二种方法是借助返回的IAsyncHandle的WaitHandle属性的WaitOne()方法实现线程同步后,执行代码,然后将要执行的代码执行后随时可调用EndInvoke方法。
 
示例代码基本没有什么改动,只是在BeginInvoke方法后执行一个ar.WaitHandle.WaitOne()方法,该方法将阻塞主线程使主线程等待返回ar的begininvoke调用的方法的线程执行完毕(不要怪我说话有点绕,我是说的详细,否则你弄不明白,仔细看这句话就明白了^o^)。
 
本着一切代码都是纸老虎的原则,请仔细分析下面的代码  其实和示例1基本无异 ,只是使用WaitOne()方法同步了一下线程而已
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace sample
{
    class AsyncDemo
    {
        public string TestMethod(int callDuration, out int threadid)
        {
            Console.WriteLine("Test Method begins");
            Thread.Sleep(callDuration);
            threadid = AppDomain.GetCurrentThreadId();
            return "MyCallTime was" + callDuration.ToString();
        }
    }
    public delegate string AsyncDelegate(int callDuration, out int threadid);
    class Program
    {
        static void Main(string[] args)
        {
            int threadID;
            AsyncDemo ad = new AsyncDemo();
            AsyncDelegate andl = new AsyncDelegate(ad.TestMethod);
            IAsyncResult ar = andl.BeginInvoke(3000, out threadID, null, null);
            Thread.Sleep(10);
            Console.WriteLine("Main Thread {0} Does Some Work",
                AppDomain.GetCurrentThreadId());
            ar.AsyncWaitHandle.WaitOne();//执行该方法时主线程将等待辅助线程执行完毕,使两线程同步后再执行以下语句
            Console.WriteLine("其实很简单");//执行一些方法
            string ret = andl.EndInvoke(out threadID, ar);//使用EndInvoke来获取返回结果和传入ref和out的变量获取修改后的实例的位置(这我就不太好用语言来表述了,你自己心领神会吧)
            Console.WriteLine("The call executed on thread {0},with return value : {1}",
                threadID, ret);
            Console.ReadLine();
        }
    }
}

C#异步调用 之 轮询异步调用完成 (三)

我觉得这个没必要称之为一种方法,和第二种方法无异,不过我感觉第二种方法是把这种方法封装起来了,而这种方法要我们自己写一个循环来不断查询异步调用的方法是否已经完成,使用该方法的人一般属于“吃饱撑的”类型的人(呵呵,我这种写这种方法的人亦如是)
其实就是把使用ar.WaitHandle.WaitOne()方法替换成一个While循环,假如没完成就睡眠10毫秒,用ar.IsCompleted属性来判断是否执行完毕
While (ar.IsCompleted == false) //假如没有执行完
{
Thread.Sleep(10);//睡眠10毫秒
}
就是把ar.WaitHandle.WaitOne()替换成上面的While循环来同步线程
代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace sample
{
class AsyncDemo
    {
        public string TestMethod(int callDuration, out int threadid)
        {
            Console.WriteLine("Test Method begins");
            Thread.Sleep(callDuration);
threadid = AppDomain.GetCurrentThreadId();
            return "MyCallTime was" + callDuration.ToString();
        }
    }
public delegate string AsyncDelegate(int callDuration, out int threadid);
class Program
    {
        static void Main(string[] args)
        {
            int threadID;
            AsyncDemo ad = new AsyncDemo();
            AsyncDelegate andl = new AsyncDelegate(ad.TestMethod);
IAsyncResult ar = andl.BeginInvoke(3000, out threadID, null, null);
Thread.Sleep(10);
Console.WriteLine("Main Thread {0} Does Some Work",
                AppDomain.GetCurrentThreadId());
while (ar.IsCompleted == false)
            {
                Thread.Sleep(10);
            }
Console.WriteLine("其实很简单");
string ret = andl.EndInvoke(out threadID, ar);
Console.WriteLine("The call executed on thread {0},with return value : {1}",
                threadID, ret);
Console.ReadLine();
        }
}
}

C#异步调用 之 使用回调函数(四)

这个和以上三种方法不同,也比较抽象难以理解,但是我想一个正常人的智商多看几遍理解起来是没有问题的。
我先说下回调函数,就是我在第一篇的时候讲过的,委托类型的BeginInvoke方法除被调用函数的参数列表外还另外加了两个参数,第一个参数就是回调方法的委托(该回调方法必须是无返回的,因为这个参数必须是System.AsyncCallBack委托,这个委托指向的是一个无返回的方法,而且这个方法只能由一个参数,参数类型是IAsyncResult,但是可以使用该参数传递任何object),第二个参数是一个param参数列表,是执行该回调方法的时候要用到的参数(应该能理解),也可以是执行BeginInvoke方法时返回的那个IAsyncResult,这样就可以在回调方法中通过,IAsyncResult.AsyncState属性来返回BeginInvoke方法所属的委托,通过这样来在回调函数中执行EndInvoke方法。
以下是示例代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace sample
{
class AsyncDemo
    {
        public string TestMethod(int callDuration, out int threadid)
        {
            Console.WriteLine("Test Method begins");
            Thread.Sleep(callDuration);
threadid = AppDomain.GetCurrentThreadId();
            return "MyCallTime was" + callDuration.ToString();
        }
    }
public delegate string AsyncDelegate(int callDuration, out int threadid);
class Program
    {
        static void Main(string[] args)
        {
            int threadID;
            AsyncDemo ad = new AsyncDemo();
            AsyncDelegate andl = new AsyncDelegate(ad.TestMethod);
IAsyncResult ar = andl.BeginInvoke(3000, out threadID,
                new AsyncCallback(CallBackMethod), andl);
Thread.Sleep(10);
Console.WriteLine("Main Thread {0} Does Some Work",
                AppDomain.GetCurrentThreadId());

            Console.ReadLine();
        }
static void CallBackMethod(IAsyncResult ar) //无返回而且只有一个IAsyncResult类型的参数ar
        {
            int j;
            AsyncDelegate andl = (AsyncDelegate)ar.AsyncState;
Console.WriteLine(andl.EndInvoke(out j, ar));
        }
}
}

C#中的异步调用剖析相关推荐

  1. Spring Boot 中启用异步调用

    在Java中一般开发程序都会同步调用的,程序中代码是一行一行执行下去的,每一行代码需要等待上一行代码执行完成才能开始执行. 在异步编程中,代码执行不是阻塞的,在方法调用中不需要等待所有代码执行完毕就可 ...

  2. Spring Boot 中的异步调用

    Spring Boot 中的异步调用 通常我们开发的程序都是同步调用的,即程序按照代码的顺序一行一行的逐步往下执行,每一行代码都必须等待上一行代码执行完毕才能开始执行.而异步编程则没有这个限制,代码的 ...

  3. JAVA中的异步调用

    1.什么是异步调用 异步调用简单理解,就是不阻塞主线程,再开辟另一个线程异步执行 main{//前置语句costTime();//后置语句 } 在上述代码中,主线程按顺序,需要依次执行前置语句,调用c ...

  4. JQuery真的不难~第六回 JQ中的异步调用方式

    回到目录 前言 今天主要讲一下JQ中的异步编程,它将ajax进行封装,在进行异步请求时显得非常容易,无论是GET,POST方式,还是text,xml,javascript,json等数据通讯都是那么的 ...

  5. 关于Vue中nextTick异步调用videoaudio的方法失效解决方案

    原文地址:https://qq282126990.github.io/2018/02/10/ nextTick JS的运行机制:JS执行是单线程的,它是基于事件循环的对于事件循环的理解大致分为以下几个 ...

  6. javascript中的异步调用,promise对象,async/await用法

    原生javascript中的的回调函数 即callback 就是通过回调函数来通知主程序 对于io 密集的非常好用:eg. file,DB读写,网络访问 异步: javascript就是个单线程语言, ...

  7. .NET MVC异步调用中的Session问题

    需要异步处理一个输入问题. 以下均代码适用 MVC4 controller 代码如下: public class TestController : AsyncController {          ...

  8. Spring中的异步任务

    为什么80%的码农都做不了架构师?>>>    问题 项目中需要异步调用第三方服务,不需要关心是否调用成功.之前在文章<Spring task的异步定时任务>中使用的xm ...

  9. Direct3D Draw函数 异步调用原理解析

    概述 在D3D10中,一个基本的渲染流程可分为以下步骤: 清理帧缓存: 执行若干次的绘制: 通过Device API创建所需Buffer: 通过Map/Unmap填充数据到Buffer中: 将Buff ...

最新文章

  1. 理解 Delphi 的类(四) - 初识类的事件
  2. [启发式搜索/A*] [SCOI2005]骑士精神题解
  3. 如何扩展Android富文本之Html标签
  4. linux后台运行命令,nohup
  5. pytorch学习——构建多元线性回归的网络结构
  6. 年度回顾 | 2019 年的 Apache Flink(文末有福利)
  7. JavaScript学习笔记之数组(一)
  8. 只有搞Java开发的才知道!javaspring菜鸟教程
  9. Eclipse ADT 进行android应用签名打包详解
  10. 几种开放源码的TCPIP协议栈
  11. 完全仿京东电商小程序的开源项目,可赚佣金
  12. android开发者mac(含M1芯片)电脑全新配置2022
  13. 转行大数据还是人工智能,哪个发展更好
  14. STM32学习记录0002-STM32初探
  15. IDEA快捷键 进行查找和批量替换
  16. Java 监控直播流rtsp协议转rtmp、hls、httpflv协议返回浏览器
  17. strcat函数 strncat函数
  18. 国标28181:什么是SDP协议
  19. 运行错误 terminate called without an active exception
  20. antv x6基类cell第五讲-文本节点可编辑

热门文章

  1. gauge 运行其他spec_Gem5(SE模式)上运行SPEC2017教程
  2. matlab实现查值,[数学建模(六)]使用MATLAB实现插值
  3. ubuntu mysql双主热备配置_MySql双主热备配置
  4. linux 中 svn 服务器搭建 重启
  5. C++中若类中没有默认构造函数,如何使用对象数组
  6. Highcharts之折线图
  7. MAVEN Error: Using platform encoding (GBK actually) to copy filtered resources.....
  8. NHibernate文档翻译--体系结构
  9. 巧用FlashPaper 让Word文档变Flash
  10. zoj 1406 Jungle Roads