C#基础之异步调用实例教程

本文实例形式展示了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处理异步函数调用,事实上是通过线程来完成的。这个过程有以下几个特点:

1.异步函数由线程完成,这个线程是.NET线程池中的线程

2.通常情况下,.NET线程池拥有500个线程(当然这个数量可以设置),每当调用BeginInvoke开始异步处理时,异步处理函数就由线程池中的某个线程负责执行,而用户无法控制具体是由哪个线程负责执行

3.由于线程池中线程数量有限,因此当池中线程被完全占用时,新的调用请求将使函数不得不等待空余线程的出现。此时,程序的效率会有所影响。

为了验证这些特点,请看下面的程序:

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.paobuke.com/develop/c-develop/pbk23543.html

相关内容

C# 当前系统时间获取及时间格式详解

SMTP客户端未通过身份验证等多种错误解决方案分享

C#中DataGridView动态添加行及添加列的方法

.NET实现定时发送邮件代码(两种方式)


游戏开发之随机概率的选择算法

C#实现把txt文本数据快速读取到excel中

C#文件和字节流的转换方法

C#排序算法的比较分析

时间: 2024-11-08 21:37:46

C#基础之异步调用实例教程的相关文章

java实现异步调用实例

在JAVA平台,实现异步调用的角色有如下三个角色: 调用者 取货凭证   真实数据 一个调用者在调用耗时操作,不能立即返回数据时,先返回一个取货凭证.然后在过一断时间后凭取货凭证来获取真正的数据. 所以连结调用者和真实数据之间的桥梁是取货凭证.我们先来看它的实现: public class FutureTicket{ private Object data = null; private boolean completed = false;  public synchronized void m

线程异步调用实例

更新content时更新Lucene的索引 Content newContent = contentService.update(content);afterContentStatusChange(newContent, ContentStatusChangeThread.OPERATE_UPDATE); private void afterContentStatusChange(Content content, Short operate){ ContentStatusChangeThread

C#基础与实例教程最简单的C#快速入门教程【转自:http://www.82011433.com/Html/?6982.html】

c#基础与实例教程最简单的C#快速入门教程 在一小时内学会C#.使用例程,简单却完整的探索C#语言的构造和特点.本文特别适合有C++基础却没有太多精力学习C#的读者. 简介 C#是一种具有C++特性,Java样式及BASIC快速建模特性的编程语言.如果你已经知晓C++语言,本文将在不到一小时的时间内带你快速浏览C#的语法.如果熟悉Java语言,Java的编程结构.打包和垃圾回收的概念肯定对你快速学习C#大有帮助.所以我在讨论C#语言构造的时候会假设你知道C++. c#基础与实例教程最简单的C#快

WinForm之BindingSource基础操作实例教程

通常我们在进行数据绑定的时候,常用的数据源有DataSet.DataTable.BindingList<T>.还有强类型数据源.今天我们来通过实例了解一下BindingSource组建,分享给大家供大家参考借鉴之用. BindingSource的两个用途: (1)首先,它提供一个将窗体上的控件绑定到数据的间接层.这是通过将 BindingSource 组件绑定到数据源,然后将窗体上的控件绑定到 BindingSource 组件来完成的.与数据的所有进一步交互(包括导航.排序.筛选和更新)都是通

网页设计Dreamweaver网页制作 商业网站建设案例课程 ASP.NET基础实例教程 淘宝开店教程

热门推荐电脑办公计算机基础知识教程 Excel2010基础教程 Word2010基础教程 PPT2010基础教程 五笔打字视频教程 Excel函数应用教程 Excel VBA基础教程 WPS2013表格教程 更多>平面设计PhotoshopCS5教程 CorelDRAW X5视频教程 Photoshop商业修图教程 Illustrator CS6视频教程 更多>室内设计3Dsmax2012教程 效果图实例提高教程 室内设计实战教程 欧式效果图制作实例教程 AutoCAD2014室内设计 Aut

网页设计 Dreamweaver网页制作 商业网站建设案例课程 ASP.NET基础实例教程 淘宝开店教程 更多&gt;

热门推荐电脑办公计算机基础知识教程 Excel2010基础教程 Word2010基础教程 PPT2010基础教程 五笔打字视频教程 Excel函数应用教程 Excel VBA基础教程 WPS2013表格教程 更多>平面设计PhotoshopCS5教程 CorelDRAW X5视频教程 Photoshop商业修图教程 Illustrator CS6视频教程 更多>室内设计3Dsmax2012教程 效果图实例提高教程 室内设计实战教程 欧式效果图制作实例教程 AutoCAD2014室内设计 Aut

AutoCAD ObjectARX(VC)开发基础与实例教程2014版光盘镜像

AutoCAD ObjectARX(VC)开发基础与实例教程2014,最新版,光盘镜像 作者:张帆 朱文俊 编著 出版社:中国电力出版社 出版时间:2014年6月 点击一下

WCF系列教程之客户端异步调用服务

本文参考自http://www.cnblogs.com/wangweimutou/p/4409227.html,纯属读书笔记,加深记忆 一.简介 在前面的随笔中,详细的介绍了WCF客户端服务的调用方法,但是那些操作全都是同步的,所以我们需要很长的时间等待服务器的反馈,如何一台服务器的速度很慢,所以客户端得到结果就需要很长的时间,试想一下,如果客户端是个web项目,那么客户体验可想而知,所以为了不影响后续代码执行和用户的体验,就需要使用异步的方式来调用服务.注意这里的异步是完全针对客户端而言的,与

BPEL 实例教程

http://www.oracle.com/technetwork/cn/articles/matjaz-bpel1-090722-zhs.html BPEL 实例教程 作者:Matjaz Juric 了解如何创建一个将一系列虚拟的.与旅行相关的 web 服务结合起来的示例业务流程,然后将其部署到 Oracle BPEL Process Manager 运行时环境. 本文相关下载  示例代码 Oracle BPEL Process Manager 和 Designer 面向 Web 服务的业务流