c#异步调用
首先来看一个简单的例子:
- 小明在烧水,等水烧开以后,将开水灌入热水瓶,然后开始整理家务
- 小文在烧水,在烧水的过程中整理家务,等水烧开以后,放下手中的家务活,将开水灌入热水瓶,然后继续整理家务
这也是日常生活中很常见的情形,小文的办事效率明显要高于小明。从C#程序执行的角度考虑,小明使用的同步处理方式,而小文则使用的异步处理方式。
同步处理方式下,事务是按顺序一件一件处理的;而异步方式则是,将子操作从主操作中分离出来,主操作继续进行,子操作在完成处理的时候通知主操作。
在C#中,异步通过委托来完成。请看下面的例子:
- class Program
- {
- static TimeSpan Boil()
- {
- Console.WriteLine("水壶:开始烧水...");
- Thread.Sleep(6000);
- Console.WriteLine("水壶:水已经烧开了!");
- return TimeSpan.MinValue;
- }
- delegate TimeSpan BoilingDelegate();
- static void Main(string[] args)
- {
- Console.WriteLine("小文:将水壶放在炉子上");
- BoilingDelegate d = new BoilingDelegate(Boil);
- IAsyncResult result = d.BeginInvoke(BoilingFinishedCallback, null);
- Console.WriteLine("小文:开始整理家务...");
- for (int i = 0; i < 20; i++)
- {
- Console.WriteLine("小文:整理第{0}项家务...", i + 1);
- Thread.Sleep(1000);
- }
- }
- static void BoilingFinishedCallback(IAsyncResult result)
- {
- AsyncResult asyncResult = (AsyncResult)result;
- BoilingDelegate del = (BoilingDelegate)asyncResult.AsyncDelegate;
- del.EndInvoke(result);
- Console.WriteLine("小文:将热水灌到热水瓶");
- Console.WriteLine("小文:继续整理家务");
- }
- }
上面的例子是一个最简单的异步调用的例子,没有对异步调用函数做任何参数传递以及返回值校验。这个例子反映了小文烧水的流程,首先小文将水壶放在炉子上,在定义好委托以后,就使用BeginInvoke方法开始异步调用,即让水壶开始烧水,于是小文便开始整理家务。水烧开后,C#的异步模型会触发由BeginInvoke方法所指定的回调函数,也就是水烧开后的处理逻辑由这个回调函数定义,此时小文将水灌入热水瓶并继续整理家务。
由此可见,在C#中实现异步调用其实并不复杂,首先创建一个异步处理函数,并针对其定义一个委托;然后在调用函数的时候,使用委托的BeginInvoke方法,指定在函数处理完成时的回调函数(如果不需要对完成事件做处理,可以给null值),并指定所需的参数(如果没有参数,也可以给null值);最后在回调函数中处理完成事件。
请注意上例回调函数中的EndInvoke调用,EndInvoke会使得调用线程阻塞,直到异步函数处理完成。显然,紧接在BeginInvoke后面的EndInvoke使用方式与同步调用等价。
EndInvoke调用的返回值也就是异步处理函数的返回值。我们把程序稍作修改,将Boil方法改成下面的形式:
- static TimeSpan Boil()
- {
- DateTime begin = DateTime.Now;
- Console.WriteLine("水壶:开始烧水...");
- Thread.Sleep(6000);
- Console.WriteLine("水壶:水已经烧开了!");
- return DateTime.Now - begin;
- }
然后将BoilingFinishedCallback改成下面的形式:
- static void BoilingFinishedCallback(IAsyncResult result)
- {
- AsyncResult asyncResult = (AsyncResult)result;
- BoilingDelegate del = (BoilingDelegate)asyncResult.AsyncDelegate;
- Console.WriteLine("(烧水一共用去{0}时间)", del.EndInvoke(result));
- Console.WriteLine("小文:将热水灌到热水瓶");
- Console.WriteLine("小文:继续整理家务");
- }
那么我们就可以在EndInvoke的时候,获得由Boil异步处理函数返回的时间值。事实上,如果定义的BoilingDelegate委托存在参数列表,那么我们也可以在BeginInvoke的时候,将所需的参数传给异步处理函数。BeginInvoke/EndInvoke函数的签名与定义它们的委托签名有关。
注意:在修改后的BoilingFinishedCallback方法中,为了得到委托实例以便获取异步处理函数的返回值,我们采用了下面的转换:
- AsyncResult asyncResult = (AsyncResult)result;
- BoilingDelegate del = (BoilingDelegate)asyncResult.AsyncDelegate;
这样才能获得调用异步处理函数的委托的实体。
.NET处理异步函数调用,事实上是通过线程来完成的。这个过程有以下几个特点:
- 异步函数由线程完成,这个线程是.NET线程池中的线程
- 通常情况下,.NET线程池拥有500个线程(当然这个数量可以设置),每当调用BeginInvoke开始异步处理时,异步处理函数就由线程池中的某个线程负责执行,而用户无法控制具体是由哪个线程负责执行
- 由于线程池中线程数量有限,因此当池中线程被完全占用时,新的调用请求将使函数不得不等待空余线程的出现。此时,程序的效率会有所影响
为了验证这些特点,请看下面的程序:
- class Program
- {
- delegate void MethodInvoker();
- static void Foo()
- {
- int intAvailableThreads, intAvailableIoAsynThreds;
- ThreadPool.GetAvailableThreads(out intAvailableThreads,
- out intAvailableIoAsynThreds);
- string strMessage =
- String.Format(@"Is Thread Pool: {0},
- Thread Id: {1} Free Threads {2}",
- Thread.CurrentThread.IsThreadPoolThread.ToString(),
- Thread.CurrentThread.GetHashCode(),
- intAvailableThreads);
- Console.WriteLine(strMessage);
- Thread.Sleep(10000);
- return;
- }
- static void CallFoo()
- {
- MethodInvoker simpleDelegate =
- new MethodInvoker(Foo);
- for (int i = 0; i < 15; i++)
- {
- simpleDelegate.BeginInvoke(null, null);
- }
- }
- static void Main(string[] args)
- {
- ThreadPool.SetMaxThreads(10, 10);
- CallFoo();
- Console.ReadLine();
- }
- }
这个程序在起始的时候将线程池中最大线程个数设置为10个,然后做15次异步调用,每个异步调用中都停留10秒钟当作处理本身所要消耗的时间。从程序的执行我们可以看到,当前10个异步调用完全开始以后,新的异步调用就会等待(注意:不是主线程在等待),直到线程池中有线程空闲出来。
c#异步调用的更多相关文章
- C#委托异步调用
参考页面: http://www.yuanjiaocheng.net/webapi/mvc-consume-webapi-get.html http://www.yuanjiaocheng.net/w ...
- Direct3D Draw函数 异步调用原理解析
概述 在D3D10中,一个基本的渲染流程可分为以下步骤: 清理帧缓存: 执行若干次的绘制: 通过Device API创建所需Buffer: 通过Map/Unmap填充数据到Buffer中: 将Buff ...
- 一个简单的webservice的demo(下)winform异步调用webservice
绕了一大圈,又开始接触winform的项目来了,虽然很小吧.写一个winform的异步调用webservice的demo,还是简单的. 一个简单的Webservice的demo,简单模拟服务 一个简单 ...
- 浅析jquery ajax异步调用方法中不能给全局变量赋值的原因及解决方法(转载)
在调用一个jquery的ajax方法时我们有时会需要该方法返回一个值或者给某个全局变量赋值,可是我们发现程序执行完后并没有获取到我们想要的值,这时很有可能是因为你用的是ajax的异步调用async:t ...
- tornado 异步调用系统命令和非阻塞线程池
项目中异步调用 ping 和 nmap 实现对目标 ip 和所在网关的探测 Subprocess.STREAM 不用担心进程返回数据过大造成的死锁, Subprocess.PIPE 会有这个问题. i ...
- .Net组件程序设计之异步调用
.Net组件程序设计之异步调用 说到异步调用,在脑海中首先想到就是BeginInvoke(),在一些常用对象中我们也会常常见到Invoke()和BeginInvoke(), 要想让自己的组件可以被客户 ...
- 谈谈RPC中的异步调用设计
RPC(远过程调用)在分布式系统中是很常用的基础通讯手段,核心思想是将不同进程之间的通讯抽象为函数调用,基本的过程是调用端通过将参数序列化到流中并发送给服务端,服务端从流中反序列化出参数并完成实际的处 ...
- (转)spring boot注解 --@EnableAsync 异步调用
原文:http://www.cnblogs.com/azhqiang/p/5609615.html EnableAsync注解的意思是可以异步执行,就是开启多线程的意思.可以标注在方法.类上. @Co ...
- C# 多线程详解 Part.02(UI 线程和子线程的互动、ProgressBar 的异步调用)
我们先来看一段运行时会抛出 InvalidOperationException 异常的代码段: private void btnThreadA_Click(object sender, ...
- ajaxpro 异步调用
AjaxPro一般默认是同步调用,异步调用只需要在方法后面加一个callback函数,直接取value属性即可.例如: MyNameSpace.Page1.getOtherConfig("A ...
随机推荐
- 查找文件是否安装以及安装路径(Ubuntu 下 )
参考:<linux下如何查看某个软件 是否安装??? 安装路径在哪???> 原文: 如果你使用rpm -ivh matlab装的, 用rpm -qa | grep matlab肯定是能够找 ...
- Javascript 笔记与总结(1-3)arguments
arguments 是函数运行时的实参列表(对象),每个函数都有自己的 arguments,但不往外层函数寻找 arguments 的相关属性,即不行成链(只有 OA 形成作用域链). 例1 < ...
- MongoDB性能监控
1.mongostat 查看运行中的mongodb实例的统计信息 重要指标说明: getmore: 通常发生在结果集比较大的查询时,第一个query返回了部分结果,后续的结果是通过getmore来获取 ...
- PHP学习(五)----jQuery和JSON数据
对于jQuery: jQuery 是一个 JavaScript 库. jQuery 极大地简化了 JavaScript 编程.
- SQL查询语句中的 limit offset(转 )
经常用到在数据库中查询中间几条数据的需求 比如下面的sql语句: ① selete * from testtable limit 2,1; ② selete * from testtable limi ...
- Abstract Algebra chapter 7
7.7:Encrypt each of the following RSA messages x so that x is divided into blocks of integers of len ...
- Android源码剖析之Framework层实战版(Ams管理Activity启动)
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 讲到实战,就不得不拿两个例子来说明,本篇想拿的是应用最广泛的两个:Ams和Wms,一个管理activ ...
- 窗口类型(Widget, Window, Dialog, Desktop, SubWindow等等)
http://doc.qt.io/qt-5/qwidget.html#windowFlags-prop http://doc.qt.io/qt-5/qtwidgets-widgets-windowfl ...
- C++控制程序只运行一个实例
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { ...
- css3常用动画效果集合01
/*由右到左进场*/ .FromRightToLeft{ -webkit-animation:FromRightToLeft 500s .2s ease both; } @-webkit-keyfra ...