浅谈C#中的异步编程
实现异步编程有4种方法可供选择,这4种访求实际上也对应着4种异步调用的模式,分为“等待”和“回调”两大类。
Title一、使用EndInvoke;
二、使用WaitHanle;
三、轮询;
四、回调。
一、使用EndInvoke
当使用BeginInvoke异步调用方法时,如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕,如下面的代码:
Ellic's Code
1 using System;2 using System.Threading;3 namespace MetadataSample4 {5 class Program6 {7 //声明一个委托类型8 public delegate void PrintDelegate(string content);9 public static void Main(string[] args)10 {11 int threadId = Thread.CurrentThread.ManagedThreadId;12 PrintDelegate printDelegate = Program.Print;13 Console.WriteLine("[主线程id:{0}]\t开始调用打印方法...",threadId);14 IAsyncResult result = printDelegate.BeginInvoke("Hello world",null,null);15 printDelegate.EndInvoke(result);1617 Console.Write("Press any key to continue . . . ");18 Console.ReadKey(true);19 }20 public static void Print(string content)21 {22 int threadId=Thread.CurrentThread.ManagedThreadId;23 Console.WriteLine("[当前线程id:{0}]\t{1}",threadId,content);24 System.Threading.Thread.Sleep(2000);25 Console.WriteLine("[当前线程id:{0}]\t打印方法调用完毕.",threadId);26 }27 }28 }
知识点回顾:
1、委托类型
委托类似于C/C++中的函数指针,它能够引用函数,只不过在C#中,委托是一个对象,并且是类型安全的,避免了函数指针的不安全性。一个委托类型的变量可以引用一个或多个方法,这些方法由委托存放于一个调用列表中,当调用一个委托类型的变量即相当于依次调用它的“调用列表”中的方法。委托是一种引用类型。
可以被引用的方法必须要满足如下规则:
Θ方法的签名和委托一致,比如方法参数的个数和类型;
Θ方法的返回值和委托一致。
委托的声明与实例化:
Ellic's Code
1 using System;2 namespace DelegateSample3 {4 public delegate void DoProcess(string msg);5 class DelegateSample6 {7 void Process(string msg)8 {9 Console.WriteLine("Process:{0}",msg );10 }11 public static void Main(string[] args)12 {13 DelegateSample sample = new DelegateSample();14 DoProcess process = new DoProcess(sample.Process);15 //DoProcess process = sample.Process;16 process("测试数据");17 Console.Write("Press any key to continue . . . ");18 Console.ReadKey(true);19 }20 }21 }2、IAsyncResult接口IasyncResult接口定义了异步操作状态应该提供的属性,它的源代码如下:1 public interface IAsyncResult2 {3 object AsycState{get;}4 WaitHandle AsyncWaitHandle{get;}5 bool CompletedSynchronously{get;}6 bool IsCompleted{get;}7 }
这些属性都是只读属性,它们的含义如下:
属性 |
返回类型 |
说明 |
AsycState |
object |
此属性返回一个对象,该对象是启动异步操作的方法的最后一个参数 |
AsyncWaitHandle |
WaitHandle |
获取用于等待异步操作完成的WaitHandle |
CompletedSynchronously |
bool |
获取一个值,该值指示异步操作是否同步完成 |
IsCompleted |
bool |
获取一个值,该值指示异步操作是否已完成 |
关于IAndsyncResult接口需要补充的是,BeginInvoke方法的返回类型以及EndInvoke方法的唯一参数均为IasyncResult接口类型。
二、使用WaitHandle
除了上面提到的方法,我们还可以使用WainHandle类型的WaitOne方法。WaitOne方法有5个重载:
n bool WaitOne()
n bool WaitOne(int millisecondsTimeout)
n bool WaitOne(TimeSpan timeout)
n bool WaitOne(int millisecondsTimeout, bool exitContext)
n bool WaitOne(TimeSpan timeout,bool exitContext)
其中,第一个不带参数的重载相当于WaitOne(-1,false),第一个参数表示等待的毫秒数,-1表示无限期等待,第二个参数表示在等待前是否退出上下文的同步域,并在稍后进行重新获取,是则为TRUE,否则为FALSE。
这些重载的核心实现为第四个重载,其他的重载就是对参数类型或个数的改变。运行代码如下:
Ellic's Code
1 using System;2 using System.Threading;34 namespace MetadataSample5 {6 class Program7 {8 //声明一个委托类型9 public delegate void PrintDelegate(string content);10 public static void Main(string[] args)11 {12 int threadId = Thread.CurrentThread.ManagedThreadId;13 PrintDelegate printDelegate = Program.Print;14 Console.WriteLine("[主线程id:{0}]\t开始调用打印方法...",threadId);15 IAsyncResult result = printDelegate.BeginInvoke("Hello world",null,null);16 //printDelegate.EndInvoke(result);17 result.AsyncWaitHandle.WaitOne(5000,false);1819 Console.Write("Press any key to continue . . . ");20 Console.ReadKey(true);21 }22 public static void Print(string content)23 {24 int threadId=Thread.CurrentThread.ManagedThreadId;25 Console.WriteLine("[当前线程id:{0}]\t{1}",threadId,content);26 System.Threading.Thread.Sleep(2000);27 Console.WriteLine("[当前线程id:{0}]\t打印方法调用完毕.",threadId);28 }29 }30 }可以看到,与EndInvoke类似,只是用WaitOne函数代码了EndInvoke而已。三、轮询之前提到的两种方法,只能等下异步方法执行完毕,在完毕之前没有任何提示信息,整个程序就像没有响应一样,用户体验不好,可以通过检查IasyncResult类型的IsCompleted属性来检查异步调用是否完成,如果没有完成,则可以适时地显示一些提示信息,如下面的代码:Ellic's Code1 using System;2 using System.Threading;3 namespace MetadataSample4 {5 class Program6 {7 //声明一个委托类型8 public delegate void PrintDelegate(string content);9 public static void Main(string[] args)10 {11 int threadId = Thread.CurrentThread.ManagedThreadId;12 PrintDelegate printDelegate = Program.Print;13 Console.WriteLine("[主线程id:{0}]\t开始调用打印方法...",threadId);14 IAsyncResult result = printDelegate.BeginInvoke("Hello world",null,null);15 while (!result.IsCompleted)16 {17 Console.WriteLine(" . ");18 Thread.Sleep(500);19 }20 Console.Write("Press any key to continue . . . ");21 Console.ReadKey(true);22 }23 public static void Print(string content)24 {25 int threadId=Thread.CurrentThread.ManagedThreadId;26 Console.WriteLine("[当前线程id:{0}]\t{1}",threadId,content);27 System.Threading.Thread.Sleep(2000);28 Console.WriteLine("[当前线程id:{0}]\t打印方法调用完毕.",threadId);29 }30 }31 }
结果如下:
四、回调
之前三种方法者在等待异步方法执行完毕后才能拿到执行的结果,期间主线程均处于等待状态。回调和它们最大的区别是,在调用BeginInvoke时只要提供了回调方法,那么主线程就不必要再等待异步线程工作完毕,异步线程在工作结束后会主动调用我们提供的回调方法,并在回调方法中做相应的处理,例如显示异步调用的结果。
先看到之前那段调用BeginInvoke的代码:
IAsyncResult result = printDelegate.BeginInvoke("Hello world",null,null);
其中,第1个参数是委托签名中的参数,后面2个参数实际是我们在回调方法中要用到的,它们分别是:
AsyncCallback callback
object @object
前者就是回调方法,它要求回调方法的签名必须符合以下条件:
返回类型为void;
参数列表只有1个参数,且为IAsyncResult 类型。
如:void callbackMethod(IasyncResult asyncResult)
回调方法代码如下:
Ellic's Code
1 using System;2 using System.Threading;3 namespace MetadataSample4 {5 class Program6 {7 //声明一个委托类型8 public delegate void PrintDelegate(string content);9 public static void Main(string[] args)10 {11 int threadId = Thread.CurrentThread.ManagedThreadId;12 PrintDelegate printDelegate = Program.Print;13 Console.WriteLine("[主线程id:{0}]\t开始调用打印方法...",threadId);14 IAsyncResult result = printDelegate.BeginInvoke("Hello world",PrintComplete,printDelegate);15 Thread.Sleep(10000);1617 Console.Write("Press any key to continue . . . ");18 Console.ReadKey(true);19 }20 public static void Print(string content)21 {22 int threadId=Thread.CurrentThread.ManagedThreadId;23 Console.WriteLine("[当前线程id:{0}]\t{1}",threadId,content);24 System.Threading.Thread.Sleep(1000);2526 }2728 private static void PrintComplete(IAsyncResult asyncResult)29 {30 if(null == asyncResult)31 {32 throw new ArgumentNullException();33 }34 int threadId = Thread.CurrentThread.ManagedThreadId;35 (asyncResult.AsyncState as PrintDelegate).EndInvoke(asyncResult);36 Console.WriteLine("[当前线程id:{0}]\t打印方法调用完毕.",threadId);37 }38 }39 }
上面的四种方法就是自己在复习C#时学到的新知识,记录下来。
浅谈C#中的异步编程相关推荐
- 浅谈js中的异步编程
转载自品略图书馆 http://www.pinlue.com/article/2020/07/0412/3110968788347.html JS异步编程模型 在理解js异步编程时, 我们先再心中想一 ...
- php中jquery ajax请求参数,浅谈Jquery中Ajax异步请求中的async参数的作用
之前不知道这个参数的作用,上网找了前辈的博客,在此收录到自己的博客,希望能帮到更多的朋友: test.html asy.js function testAsync{ var temp; $.ajax( ...
- 浅谈Android中的异步加载之ListView中图片的缓存及优化三
隔了很久没写博客,现在必须快速脉动回来.今天我还是接着上一个多线程中的异步加载系列中的最后一个使用异步加载实现ListView中的图片缓存及其优化.具体来说这次是一个综合Demo.但是个人觉得里面还算 ...
- 浅谈JAVA中如何利用socket进行网络编程(二)
转自:http://developer.51cto.com/art/201106/268386.htm Socket是网络上运行的两个程序间双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以 ...
- c语言在数学方面的应用编程,浅谈数学在C语言编程中的应用.doc
浅谈数学在C语言编程中的应用 浅谈数学在C语言编程中的应用 [][]C语言对学习者的数学基础要求较高对一部分学生来说学好C语言有一定的困难.本文就本专业知识和自身对C语言的学习经验对数学在C语言编程中 ...
- 浅谈JS中常见的问题(三)
往期文章目录 浅谈JS中常见的问题(一) 浅谈JS中常见的问题(二) JS知识总结 往期文章目录 前言 11. 同步和异步的区别 12. JS 判断变量类型的几种方法 13. 如何阻止事件冒泡与默认事 ...
- 浅谈Android中的MVP与动态代理的结合
浅谈Android中的MVP与动态代理的结合 本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 在Android开发平台上接触MVP足足算起来大概已经有一个年头左右.从最开始到现在经 ...
- python sys模块作用_浅谈Python中的模块
模块 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式.在Python中,一个.py文件就称之为一个模块(Mod ...
- python中 是什么类型_浅谈python中的变量默认是什么类型
浅谈python中的变量默认是什么类型 1.type(变量名),输出的结果就是变量的类型: 例如 >>> type(6) 2.在Python里面变量在声明时,不需要指定变量的类型,变 ...
最新文章
- linux 用户和权限管理
- HDLBits 系列(15) 如何设计一个双边沿采样的电路?
- 彻底理解Intel FPGA时序约束---最后总结(三)
- 公众号jdk 获取手机号_如何获取公众号推文封面图
- 利用Fiddler抓包调试工具,实现mock数据特殊场景深度测试(二)
- EPIC《禅意花园》项目开放下载
- 国家铁路调度中心在哪_博慈46寸液晶拼接屏打造上海铁路局南翔站指挥中心显示系统...
- selenium的运行时异常
- sublime设置代码缩进
- 网页内嵌多媒体内容的完美实现
- 大学计算机基础操作教程文本框,大学计算机基础教程及实训指导教学课件 薛晓萍 第六部分 演示文稿制作软件PowerPoint 2003.ppt...
- Linux安装wget
- Java学习到什么程度可以找第一份工作?
- 怎么修改windows10在cmd下的用户名为英文名
- uniapp获取微信头像和昵称
- python泰勒公式_泰勒公式和Gamma函数
- rediscrawlSpider使用-亚马逊图书案例
- android 手机数据备份,怎么备份手机数据 手机数据备份方法介绍
- SQL数据库实验报告一
- vs2012编程中输出中文出现乱码