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

15 篇文章 0 订阅
14 篇文章 0 订阅

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

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

一、简单的串行执行程序
我们先来看一个简单的程序:定义了一个int Add(int num),传入循环的次数num,返回循环相加的结果sum。Step 1.Main方法调用Add方法,循环执行了2次,所以延时了2s,返回结果sum=1,打印 Result:1;Step 2.Main方法循环执行了3次,延时了3s。

我们可以从结果中看到: (3s)是串行执行的,那么我们有没有一种方法使这两种操作并行执行了?(3s中之内搞定这两个耗时操作)。答案是可以用APM。 下面我们用APM方式来节省2s的时间。
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,可以参考我之前写的博客,在这里就不再说明了,对于第三个知识点,是因为委托定义了两个异步方法BeginInvoke和EndInvoke。我们可以先看看泛型委托的定义:

 /// <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的可能抛出的异常。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值