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

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

C#多线程之旅目录:

C#多线程之旅(1)——介绍和基本概念

C#多线程之旅(2)——创建和开始线程

C#多线程之旅(3)——线程池

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

C#多线程之旅(5)——同步机制介绍

C#多线程之旅(6)——详解多线程中的锁

更多文章正在更新中,敬请期待......

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/

关于作者:专注于微软平台的项目开发。如有问题或建议,请多多赐教!

版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信

声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!

C#多线程之旅(4)——APM初探的更多相关文章

  1. C#多线程之旅(3)——线程池

    v博客前言 先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很 ...

  2. C#多线程之旅(1)——介绍和基本概念

    原文地址:C#多线程之旅(1)——介绍和基本概念 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C#多线程之旅(2)——创建和开始线程 C#多线程之旅(3)——线程池 C#多线程之旅( ...

  3. C#多线程之旅(7)——终止线程

    先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很多问题.   ...

  4. C#多线程之旅~上车吧?

    前言:前几天,写了一篇关于多线程使用的文章,[线程使用]用法得到不少博友的好评,博主这几天加班写文章,把剩下的高级使用给写完,期望可以得到博友的追赞吧,那么废话不多说,开始我们的C#高级用法之旅!! ...

  5. 【10】Python urllib、编码解码、requests、多线程、多进程、unittest初探、__file__、jsonpath

    1 urllib urllib是一个标准模块,直接import就可以使用 1.1get请求 from urllib.request import urlopen url='http://www.nnz ...

  6. [转]NHibernate之旅(7):初探NHibernate中的并发控制

    本节内容 什么是并发控制? 悲观并发控制(Pessimistic Concurrency) 乐观并发控制(Optimistic Concurrency) NHibernate支持乐观并发控制 实例分析 ...

  7. NHibernate之旅(7):初探NHibernate中的并发控制

    本节内容 什么是并发控制? 悲观并发控制(Pessimistic Concurrency) 乐观并发控制(Optimistic Concurrency) NHibernate支持乐观并发控制 实例分析 ...

  8. NHibernate之旅(18):初探代码生成工具使用

    本节内容 引入 代码生成工具 结语 引入 我们花了大量的篇幅介绍了相关NHibernate的知识.一直都是带着大家手动编写代码,首先创建数据库架构.然后编写持久化类和映射文件,最后编写数据操作方法.測 ...

  9. 多线程之旅(Thread)

    在上篇文章中我们已经知道了多线程是什么了,那么它到底可以干嘛呢?这里特别声明一个前面的委托没看的同学可以到上上上篇博文查看,因为多线程要经常使用到委托.源码 一.异步.同步 1.同步(在计算的理解总是 ...

随机推荐

  1. JS变量和函数的一些理解

    今日看了下JS变量的一些文章,有些感触,把自己总结的一些写出来. JS初始化的过程1.JS解释器执行代码之前,创建全局变量2.用预定义的值和函数来初始化全局对象中的属性,3.搜索函数外的var声明,创 ...

  2. PYTHON学习之路_PYTHON基础(8)

    学习内容: Python模块介绍 1.经典类 or 新式类 2.抽象接口 3.静态方法.类方法.属性方法 4.反射 5.异常处理 6.socket编程初识 7.用socket实现get.put文件等功 ...

  3. C# final project

    Problem Statement You are tasked with developing a task manager. The task manager will allow people ...

  4. php tools for visual studio 2013 完美 破解 Cracker

    PHP Tools for Visual Studio 2013,这个是 目前在 Visual Studio 2010/2012/2013 中 下最好用的php插件了,  破解 好的 Cracker  ...

  5. codeforces 484E

    题意:给定n<=105的数组h,有m<=105的询问,每个询问为l,r,w求[l,r]区间内连续w个的最小高度最大是多少.. 思路:首先把h数组从大到小排序,然后用建立一个可持久化的下标线 ...

  6. OpenCv编程

    (1)用OpenCv加载.显示.保存图片: //加载图片 IplImage* m_img;//定义IplImage格式的图片头指针: m_img=cvLoadImage(m_imgLoc);//装载m ...

  7. mongoDB研究笔记:分片集群部署

    前面几篇文章的分析复制集解决了数据库的备份与自动故障转移,但是围绕数据库的业务中当前还有两个方面的问题变得越来越重要.一是海量数据如何存储?二是如何高效的读写海量数据?尽管复制集也可以实现读写分析,如 ...

  8. 微软connect教程系列—EntityFramework7(三)

      随着Asp.NET5的开源,以及跨平台,ORM框架EF7也与时俱进,支持asp.net core,也支持关系型数据库和非关系型数据库,以及在linux和mac上跨平台使用. 下面演示的即通过使用E ...

  9. .Net平台下,分布式文件存储的实现

    遇到的问题 对于Web程序,使用一台服务器的时候,客户端上传的文件一般也都是存储在这台服务器上.但在集群环境中就行不通了,如果每个服务器都存储自己接受到的文件,就乱套了,数据库中明明有这个附件的记录, ...

  10. .net开发笔记(十三) Winform常用开发模式第一篇

    上一篇博客最后我提到“异步编程模型”(APM),之后本来打算整理一下这方面的材料然后总结一下写篇文章与诸位分享,后来在整理的过程中不断的延伸不断地扩展,发现完全偏离了“异步编程”这个概念,前前后后所有 ...