当我们用到C#类许多耗时的函数XXX时,总会存在同名的类似BeginXXX,EndXXX这样的函数。

例如Stream抽象类的Read函数就有

        public abstract int Read(byte[] buffer, int offset, int count);

        public virtual IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state);

        public virtual IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state);

这也就是所谓的APM异步编程模型,基于委托实现,其实就是启动了一个后台线程(主线程结束,则该线程结束),其中IAsyncResult就是异步状态接口,用来检测异步是否完成。

代码模拟场景1:

每到大热天的中午就不想动,出门就是一身汗,所以一般午餐时间我都选择定外卖,正好等外卖这段时间还可以完善一下上午的工作内容。这就相当于委托一名外卖小哥异步帮我送一份快餐过来,这段时间我继续干我的事情。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace BeginInvoke
{
class Program
{
//声明一个送外卖的委托类型
private delegate int DeliveryDelegate(string foodname);
static void Main(string[] args)
{
Console.WriteLine("天气太热,带电话叫外卖小哥送一份番茄炒蛋"); //声明一个外卖小哥,委托他去帮我拿午餐。
DeliveryDelegate DeliveryBoy = new DeliveryDelegate(GetFood); //开始CALL电话(异步调用,由于还没用到回调函数,后两个参数填空)
IAsyncResult ar = DeliveryBoy.BeginInvoke("番茄炒蛋", null, null); //继续干自己的事……
Console.WriteLine("完善上午的工作~大概5分钟完成");
Thread.Sleep();
Console.WriteLine("完善20%");
Thread.Sleep();
Console.WriteLine("完善40%");
Thread.Sleep();
Console.WriteLine("完善60%");
Thread.Sleep();
Console.WriteLine("完善80%");
Thread.Sleep();
Console.WriteLine("完善100%");
Console.WriteLine("完善工作完成");//但是外卖还没到
Console.WriteLine("等外卖……好饿,估计还要5分钟才到"); //此时调用EndInvoke会阻塞住线程直到异步调用完成,这时相当于我就主动蹲在门口等外卖小哥送上门,如果小哥先到,只能在门口等我办完事~。
int money = DeliveryBoy.EndInvoke(ar);
Console.WriteLine("给快递小哥" + money + "元,开吃");
} /// <summary>
/// 获取食物
/// </summary>
/// <param name="foodname">食物名</param>
/// <returns>价格</returns>
private static int GetFood(string foodname)
{
Console.WriteLine("外卖小哥顶着烈日送餐ing,预计10分钟后到");
Thread.Sleep();
Console.WriteLine("外卖到达~" + foodname);
//不管什么菜一律10元钱!
return ;
}
}
}

运行结果:

天气太热,带电话叫外卖小哥送一份番茄炒蛋
完善上午的工作~大概5分钟完成
外卖小哥顶着烈日送餐ing,预计10分钟后到
完善20%
完善40%
完善60%
完善80%
完善100%
完善工作完成
等外卖……好饿,估计还要5分钟才到
外卖到达~番茄炒蛋
给快递小哥10元,开吃

注:如果使用ar.AsyncWaitHandle.WaitOne();可以设置指定等待时间间隔

            if (ar.AsyncWaitHandle.WaitOne())//也会阻塞住线程直到异步调用完成,EndInvoke之后会自动收到Set信号。
{
int money = DeliveryBoy.EndInvoke(ar);
Console.WriteLine("给快递小哥" + money + "元,开吃");
//如果调用ar.AsyncWaitHandle.WaitOne();,记得EndInvoke后要主动Close哟!
ar.AsyncWaitHandle.Close();
}

代码模拟场景2:

之前的场景,如果我没有做完工作,那么外卖小哥只能在门口一直等我做完事情(没办法通知我外卖到了,只有我主动去检查),这个时候回调函数就派上用处了,我就再也不用担心外卖什么时候到,因为我又委托一个人专门帮我在门口盯着外卖小哥!

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace BeginInvoke
{
class Program
{
//声明一个送外卖的委托类型
private delegate int DeliveryDelegate(string foodname);
static void Main(string[] args)
{
Console.WriteLine(DateTime.Now.ToString());
Console.WriteLine("天气太热,带电话叫外卖小哥送一份番茄炒蛋"); //声明一个外卖小哥,委托他去帮我拿午餐。
DeliveryDelegate DeliveryBoy = new DeliveryDelegate(GetFood); //开始CALL电话(异步调用,AsyncCallback其实也是一个delegate类型,实例化delegate委托一个人专门帮我在门口盯着外卖小哥)
IAsyncResult ar = DeliveryBoy.BeginInvoke("番茄炒蛋", new AsyncCallback(GetFoodCallback), "番茄炒蛋"); //继续干自己的事……
Console.WriteLine("完善上午的工作~大概5分钟完成");
Thread.Sleep();
Console.WriteLine("完善20%");
Thread.Sleep();
Console.WriteLine("完善40%");
Thread.Sleep();
Console.WriteLine("完善60%");
Thread.Sleep();
Console.WriteLine("完善80%");
Thread.Sleep();
Console.WriteLine("完善100%");
Console.WriteLine("完善工作完成");//但是外卖还没到 Console.WriteLine("外卖估计还要5分钟才到,时间不等人,撸一盘"); //中途外卖到了,回调函数帮我付钱拿外卖,我继续撸。
Console.WriteLine("LOL……一局10分钟");
for (int i = ; i < ; i++)
{
Thread.Sleep();
Console.WriteLine("过去了1分钟");
} Console.WriteLine("LOL拿到了首胜!,吃饭"); if (ar.IsCompleted)
{
Console.WriteLine("好吃~");
}
} /// <summary>
/// 获取食物
/// </summary>
/// <param name="foodname">食物名</param>
/// <returns>价格</returns>
private static int GetFood(string foodname)
{
Console.WriteLine("外卖小哥顶着烈日送餐ing,预计10分钟后到");
Thread.Sleep();
Console.WriteLine("外卖到达~" + foodname);
//不管什么菜一律10元钱!
return ;
} /// <summary>
/// 异步完成,回调(完成时执行)
/// 回调在 ThreadPool 线程上执行。 ThreadPool 线程是后台线程,这些线程不会在主线程结束后保持应用程序的运行,因此示例的主线程必须休眠足够长的时间以便回调完成。
/// </summary>
/// <param name="ar">异步状态</param>
private static void GetFoodCallback(IAsyncResult ar)
{
AsyncResult result = (AsyncResult)ar;
DeliveryDelegate dd = result.AsyncDelegate as DeliveryDelegate;
int money = dd.EndInvoke(ar);
string foodname = ar.AsyncState as string;
Console.WriteLine("拿外卖!" + foodname + ",一共" + money + "元");
Console.WriteLine("付钱");
}
}
}

运行结果:

天气太热,带电话叫外卖小哥送一份番茄炒蛋
完善上午的工作~大概5分钟完成
外卖小哥顶着烈日送餐ing,预计10分钟后到
完善20%
完善40%
完善60%
完善80%
完善100%
完善工作完成
外卖估计还要5分钟才到,时间不等人,撸一盘
LOL……一局10分钟
过去了1分钟
过去了1分钟
过去了1分钟
过去了1分钟
过去了1分钟
外卖到达~番茄炒蛋
拿外卖!番茄炒蛋,一共10元
付钱
过去了1分钟
过去了1分钟
过去了1分钟
过去了1分钟
过去了1分钟
LOL拿到了首胜!,吃饭
好吃~

参考:

https://msdn.microsoft.com/zh-cn/library/ms228963(v=vs.110).aspx

https://msdn.microsoft.com/zh-cn/library/system.iasyncresult(v=vs.110).aspx

https://msdn.microsoft.com/zh-cn/library/2e08f6yc(v=vs.110).aspx

【温故知新】c#异步编程模型(APM)--使用委托进行异步编程的更多相关文章

  1. 转:[你必须知道的异步编程]——异步编程模型(APM)

    本专题概要: 引言 你知道APM吗? 你想知道如何使用异步编程模型编写代码吗? 使用委托也可以实现异步编程,你知道否? 小结 一.引言 在前面的C#基础知识系列中介绍了从C#1.0——C#4.0中一些 ...

  2. [你必须知道的异步编程]——异步编程模型(APM)

    本专题概要: 引言 你知道APM吗? 你想知道如何使用异步编程模型编写代码吗? 使用委托也可以实现异步编程,你知道否? 小结 一.引言 在前面的C#基础知识系列中 介绍了从C#1.0——C#4.0中一 ...

  3. 一、异步编程模型(APM)

    一.概念 APM即异步编程模式的简写(Asynchronous Programming Model).大家在写代码的时候或者查看.NET 的类库的时候肯定会经常看到和使用以BeginXXX和EndXX ...

  4. 异步编程模型(APM)模式

    什么是APM .net 1.0时期就提出的一种异步模式,并且基于IAsyncResult接口实现BeginXXX和EndXXX类似的方法. .net中有很多类实现了该模式(比如HttpWebReque ...

  5. 异步编程:IAsyncResult异步编程模型 (APM)

    http://www.cnblogs.com/heyuquan/archive/2013/03/22/2976420.html

  6. Asynchronous Programming Using Delegates使用委托进行异步编程

    http://msdn.microsoft.com/zh-cn/library/22t547yb(v=vs.110).aspx https://github.com/chucklu/Test/tree ...

  7. C#异步编程の-------异步编程模型(APM)

    术语解释: APM               异步编程模型, Asynchronous Programming Model EAP                基于事件的异步编程模式, Event ...

  8. .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)

    本文内容 异步编程类型 异步编程模型(APM) 参考资料 首先澄清,异步编程模式(Asynchronous Programming Patterns)与异步编程模型(Asynchronous Prog ...

  9. 【温故而知新-万花筒】C# 异步编程 逆变 协变 委托 事件 事件参数 迭代 线程、多线程、线程池、后台线程

    额基本脱离了2.0 3.5的时代了.在.net 4.0+ 时代.一切都是辣么简单! 参考文档: http://www.cnblogs.com/linzheng/archive/2012/04/11/2 ...

随机推荐

  1. Linux软件安装方法小结(附:rpm详解)(转载)

    在使用Linux系统的过程中,软件包的安装是避免不了的,在Linux下,软件安装程序的种类很多,安装方法也各式各样,(舒适性自然比不上windows :-))不过我们常见的软件包有两种: 1)含有软件 ...

  2. ios瀑布流

    http://blog.csdn.net/shenjx1225/article/details/9037631

  3. 树链剖分 - BZOJ 1036: [ZJOI2008]树的统计Count

    这是树链剖分的入门题,也是我学树链剖分的第一题. 树链剖分:就是把树中和线段树联系起来,求(u,v)路径中权值的最大值和其路径的权值和. 入门blog:http://blog.sina.com.cn/ ...

  4. ubuntu安装后没有root密码

    新安装的ubuntu没有设置root密码,也就不能登录到root账户下.要想设置root密码需要在当前账户下输入sudo passwd,然后输入当前用户的密码,然后输入两次root的新密码,即可完成r ...

  5. 有关npm rum的3个简洁技巧

    [编者按]本文作者为来自 MongoDB 的 NodeJS 工程师 Valeri Karpov.Valeri 专注于维护常见的 Mongoose ODM,是<Professional Angul ...

  6. URAL1018 Binary Apple Tree(树dp)

    组队赛的时候的一道题,那个时候想了一下感觉dp不怎么好写呀,现在写了出来,交上去过了,但是我觉得我还是应该WA的呀,因为总感觉dp的不对. #pragma warning(disable:4996) ...

  7. Apache设置禁止访问网站目录(目录列表显示文件)

    默认apache在当前目录下没有index.html入口就会显示目录.让目录暴露在外面是非常危险的事,如下操作禁止apache显示目录,希望文章对各位有帮助. 进入apache的配置文件 httpd. ...

  8. ExtJs布局之border

    <!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...

  9. eclipse下python的selenium自动化环境的搭建

    前提:安装python,我用的2.7.8版本,并在环境变量path里设置;E:\Python1.解压setuptools(Python包管理工具),cmd到目录执行python setup.py in ...

  10. 8天学通MongoDB——第二天 细说增删查改

    原文地址:http://www.cnblogs.com/huangxincheng/archive/2012/02/19/2357846.html 看过上一篇,相信大家都会知道如何开启mongodb了 ...