C#多线程之旅(4)——APM初探

源码地址:https://github.com/Jackson0714/Threads

原文地址:C#多线程之旅(4)——APM初探

v博客前言

先交代下背景,前面几张内容主要是介绍多线程的基本知识,这一章是因为正好接触到了APM(异步编程模型),发现APM真的很强大,其中有部分知识点涉及到了委托的BeginInvoke/EndInvoke,就由衷地想写下APM相关的知识。

v写在前面

强大的异步处理模型,不得不被它折服!

v正文开始

一、简单的串行执行程序

 我们先来看一个简单的程序:

定义了一个int Add(int num),传入循环的次数num,返回循环相加的结果sum。

Step 1.Main方法调用Add方法,循环执行了2次,所以延时了2s,返回结果sum=1,打印 Result:1;

Step 2.Main方法循环执行了3次,延时了3s。

友情提醒:如果觉得不想阅读多彩的Console打印代码,可以选择查看下面折叠的code区域。查看简洁版

 去掉颜色打印的code简洁版

 让我们看看这个程序的运行结果:

 我们可以从结果中看到:

  1.执行Add方法,是主线程执行Add方法;

  2.执行Main方法,是主线程执行Main方法;

  3.这中限时操作可以称为“计算限制的异步操作”;

  4.Add方法中模拟耗时操作(2s)和Main方法中模拟耗时操作(3s)是串行执行的,那么我们有没有一种方法使这两种操作并行执行了?(3s中之内搞定这两个耗时操作)。答案是可以用APM。

 下面我们用APM方式来节省2s的时间。

 二、使用委托来实现APM

2.1 预备知识

我们使用泛型委托来实现APM,那么我们需要点预备知识(对委托很熟练的同学们可以跳过预备知识):

  1.什么是委托?

  2.什么是泛型委托?

  3.为什么使用委托来实现APM?

对于这知识点1、2,可以参考我之前写的博客,在这里就不再说明了,

不惧面试:委托

对于第三个知识点,是因为委托定义了两个异步方法BeginInvokeEndInvoke

我们可以先看看泛型委托的定义:

/// <summary>
/// 定义一个泛型委托
/// </summary>
/// <typeparam name="T">输入参数</typeparam>
/// <typeparam name="TResult">返回值</typeparam>
/// <param name="arg">输入参数</param>
/// <returns name="TResult">返回值</returns>
private delegate TResult Func<T, TResult>(T arg);

对于这个定义,C#编译器会将这行代码编译成一个类定义,它的逻辑定义如下:

public sealed class Func<T, TResult> : MulticastDelegate
{
	public Func(Object obj, IntPtr method);
	public TResult Invoke(T arg);
	public IAsyncResult BeginInvoke(T arg, AsyncCallback callback, Object obj);
	public TResult EndInvoke(IAsyncResult result);
}

定义一个委托时,会生成一个BeginInvoke和EndInvoke方法的类。

当定义下面的委托时

public delegate void myDelegate(int value);

通过反编译工具ILSpy查看结果:

BeginInvoke:

  1.第一个参数arg为委托定义相同的参数(可以为两个参数arg,和委托的签名相同),可以传入到委托引用的方法;

  2.倒数第二个参数callback为回调方法,当BeginInvoke方法执行完后,会立即调用回调方法,如果callback=null,则不调用回调方法;

  3.倒数第一个参数object给EndInvoke用的。

  4.返回值为IAsyncResult类型的接口对象(实际上是AsynResult的类型实例)。该接口对象用途

    a.传递参数,它包含了对调用了BeginInvoke的委托的引用,这里是Add方法的int类型的输入参数;

    b.包含了BeginInvoke()的最后一个Object类型的参数

    c.它可以鉴别是哪个方法的哪一次调用,因为通过同一个委托变量可以对同一个方法调用多次。

EndInvoke

  1.第一个参数接收BeginInvoke返回的IAnsyResult;

  2.返回的TResult为委托引用的方法的返回值,这里是Add方法的int类型返回值

2.2 用委托来实现APM的原理

2.3 动手写个实现了APM的Code

通过上面的流程图,相信我们对委托来实现APM有了一定的理解,再来读读code,相信能更快地理解。注释仅作参考,有问题可以回复我哦!

让我们看看结果:

 注意:

  1.必须先将IAsyncResult转换为AsyncResult,才能获取到引用的委托,因为它没有包含在IAsyncResult接口的定义中;

  2.Add方法的调用,AddCallback方法都是线程池线程调用的;

  3.BeginInvoke的object参数可以为任何类型,例子中传递的是string类型的参数"I'm here!";

  4.主线程执行的for循环和Add方法中线程是同时进行的,交替打印结果;

  5.当异步的Add方法没有执行完毕,调用EndInvoke,则会阻塞当前线程池线程,只有异步方法执行完毕后,才会继续执行的代码;

  6.Add方法执行完后,会自动调用回调方法AddCallback;

  7.在调用EndInvoke可能抛出异常,所以需要加try/catch/finally,捕获EndInvoke的可能抛出的异常。

v写在最后

因为只是刚开始接触APM相关的知识,所以本篇只是写初探的内容,后面的章节会更多地介绍这方面的内容。希望得到园友们的支持!

作  者: Jackson0714 出  处:http://www.cnblogs.com/jackson0714/ 关于作者:专注于微软平台的项目开发。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:您的鼓励是作者坚持原创和持续写作的最大动力!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏吾爱乐享

short s=1;s=s+1; short s=1;s+=1; 有区别么?? 如果有的话区别是什么?

15930
来自专栏北京马哥教育

提升Python程序性能的7个习惯

使用局部变量替换模块名字空间中的变量,例如 ls = os.linesep。一方面可以提高程序性能,局部变量查找速度更快;另一方面可用简短标识符替代冗长的模块变...

9000
来自专栏破晓之歌

python 模板实现-引擎的编写(有时间试一下)

1.模板的编写:https://blog.csdn.net/MageeLen/article/details/68920913

21040
来自专栏Pythonista

python中的函数

初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因变...

16140
来自专栏小樱的经验随笔

线段树区间更新操作及Lazy思想(详解)

此题题意很好懂:  给你N个数,Q个操作,操作有两种,‘Q a b ’是询问a~b这段数的和,‘C a b c’是把a~b这段数都加上c。 需要用到线...

68570
来自专栏微信公众号:Java团长

Java堆和栈的区别

在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作...

26330
来自专栏积累沉淀

JDK动态代理的底层实现原理

JDK动态代理的底层实现原理      动态代理是许多框架底层实现的基础,比如Spirng的AOP等,其实弄清楚了动态代理的实现原理,它就没那么神奇了,下面就来...

60270
来自专栏大闲人柴毛毛

深入Java虚拟机——JVM内存详解

在C++中,程序员拥有每一个对象的所有权,但与此同时还肩负着释放对象内存空间的责任;而Java由于有了虚拟机的帮助,程序员拥有对象的所有权的同时不再需要释放对象...

413120
来自专栏刘君君

JVM Specification notes 1 -Jvm Structure

摘要: Jvm Structure 正文: Java 虚拟机结构 Class文件格式 数据类型 原始类型(基本类型) 数值类型{整数[byte8 short1...

38070
来自专栏公众号_薛勤的博客

Java虚拟机性能监测工具Visual VM与OQL对象查询语言

Visual VM是一个功能强大的多合一故障诊断和性能监控的可视化工具,它集成了多种性能统计工具的功能,使用 Visual VM 可以代替jstat、jmap、...

28430

扫码关注云+社区

领取腾讯云代金券