VS2010是经常阻塞UI线程的应用程序之一。例如用vs2010打开一个包含数百个项目的解决方案,可以要等待很长时间(感觉像卡死),自从vs2012情况得到了改善,项目在后台进行了异步加载。

一、同步模式

二、异步模式

三、基于事件的异步模式

四、基于任务的异步模式

4.5以后更新基于任务的异步模式。

1.最基本的任务

普通方法

  1. public string A()
  2. {
  3. return "abc";
  4. }

(1)基于任务的模式带有 Async后缀的方法,并返回一个Task类型。

  1. public Task<string> AAsync()
  2. {
  3. return Task.Run(() => A());
  4. }

其中Task<string>是一个返回字符串的任务。

用Task.Run方法在线程池上执行一个方法,并返回一个任务对象。

(2)使用关键字await来调用返回的任务 ,await关键字需要用带 Async修饰符的方法声明.

  1. public async void BAsync()
  2. {
  3. string str = await AAsync();
  4. Console.WriteLine("abc");
  5. }

Async修饰符只能用于返回Task<>或者void的方法。而且Async不能修饰Main。await只能返回Task的方法

完整代码,执行一个异步任务

例1

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. Program p = new Program();
  6. p.BAsync();
  7. Console.ReadKey();
  8. }
  9. public string A()
  10. {
  11. return "abc";
  12. }
  13. public Task<string> AAsync()
  14. {
  15. return Task.Run(() => A());
  16. }
  17. public async void BAsync()
  18. {
  19. string str = await AAsync();
  20. Console.WriteLine("abc");
  21. }
  22. }

任务完成后执行

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. Program p = new Program();
  6. p.C();
  7. Console.ReadKey();
  8. }
  9. public string A()
  10. {
  11. return "abc";
  12. }
  13. public Task<string> AAsync()
  14. {
  15. return Task.Run(() => A());
  16. }
  17. public void C()
  18. {
  19. //用task对象接收返回对象
  20. Task<string> t1 = AAsync();
  21. //任务完成后调用的代码
  22. t1.ContinueWith(t =>
  23. {
  24. Thread.Sleep();
  25. string s = t.Result;
  26. Console.WriteLine(s);
  27. });
  28. Console.WriteLine("efg");
  29. }
  30. }

(3)使用await async关键字,当await完成之后,不需要进行任何特别处理,就能访问UI线程

???

(4)使用多个异步方法

按顺序调用异步

修改例1 的BAsync()方法

  1. public async void BAsync()
  2. {
  3. string str = await AAsync();
  4. string str2 = await AAsync() + "d";
  5. Console.WriteLine("{0},{1}",str,str2);
  6. }

如果一个异步依赖另一个异步方法的结果,await非常有用,如果完全独立,每个异步方法都不使用await,整个方法将更快返回结果

组合器

一个组合器可以接受多个同一类型的参数,并返回同一类型的值。

  1. public async void BAsync()
  2. {
  3. Task<string> T1 = AAsync();
  4. Task<string> T2 = AAsync();
  5. //等待,直到两个任务完成,返回task
  6. await Task.WhenAll(T1,T2);
  7. Console.WriteLine("{0},{1}", T1.Result, T2.Result);
  8. //也可用于返回数组
  9. string[] res= await Task.WhenAll(T1, T2);
  10. Console.WriteLine("{0},{1}", res[], res[]);
  11. //其中一个完成就返回task
  12. await Task.WhenAny(T1, T2);
  13. }

(5)转换异步模式

2.错误处理

3.取消

五、委托进行异步编程

1.BeginInvoke()
异步启动委托, 参数与要执行的方法的参数相同,另加两个可选参数
第一个参数是一个 AsyncCallback 委托,此委托引用在异步调用完成时要调用的方法。
第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。
BeginInvoke 将立即返回,而不会等待异步调用完成。
BeginInvoke 返回可用于监视异步调用的进度的 IAsyncResult。
IAsyncResult 对象 =委托对象.BeginInvoke(定义委托时有几个参数,AsyncCallback ,类的对象);

2.EndInvoke()
EndInvoke 方法用于检索异步调用的结果,它可以在调用 BeginInvoke之后的任意时间调用。
如果异步调用尚未完成,那么 EndInvoke 将阻止调用线程,直到完成异步调用。
这种方式非常适合执行文件或网络操作。

(1)使用 EndInvoke 等待异步调用

在控制台下运行

新建了一个测试类,一个用来同步,一个用来异步。

  1. class Program
  2. {
  3. public delegate string delegateClass(int time);
  4. static void Main(string[] args)
  5. {
  6. TextClass textClass = new TextClass();
  7. //把要执行的异步方法存入委托
  8. delegateClass testMethod = new delegateClass(textClass.asynMethod);
  9. //启动异步委托,参数一有没有取决于定义委托时的参数有没有
  10. IAsyncResult result = testMethod.BeginInvoke(, null, null);
  11. //当异步委托结束后,把该委托返回的值回传给str
  12. string str1 = testMethod.EndInvoke(result);
  13. Console.WriteLine(str1);
  14. Console.WriteLine("...............");
  15. //运行同步方法
  16. string str2 = textClass.synMethod();
  17. Console.WriteLine(str2);
  18. Console.ReadKey();
  19. }
  20. }
  21. //测试类
  22. class TextClass
  23. {
  24. //用来同步
  25. public string synMethod(int time)
  26. {
  27. Console.WriteLine("启动同步方法");
  28. Thread.Sleep(time);
  29. Console.WriteLine("结束同步方法");
  30. return "同步返回";
  31. }
  32. //用来异步
  33. public string asynMethod(int time)
  34. {
  35. Console.WriteLine("启动异步方法");
  36. Thread.Sleep(time);
  37. Console.WriteLine("结束异步方法");
  38. return "异步返回";
  39. }
  40. }

运行结果:

发现结果异步操作执行后,才执行的同步操作。

然后注释掉“等待异步调用的方法”

  1. //string str1 = testMethod.EndInvoke(result);
  2. //Console.WriteLine(str1);

在运行:

EndInvoke()方法会把所在的线程卡住(阻塞)

所以如果在winfrom下运行EndInvoke(),在异步未执行完的条件下会把界面卡死。EndInvoke方法不能和用户界面在同一个线程下。

(2)对异步调用的完成情况进行轮询

  1. public delegate string delegateClass(int time);
  2. static void Main(string[] args)
  3. {
  4. TextClass textClass = new TextClass();
  5. //把要执行的异步方法存入委托
  6. delegateClass testMethod = new delegateClass(textClass.asynMethod);
  7. //启动异步委托
  8. IAsyncResult result = testMethod.BeginInvoke(, null, null);
  9. //如果异步为执行完成,会不断循环执行此方法。
  10. while (result.IsCompleted == false)
  11. {
  12. //Thread.Sleep(350);
  13. Console.Write("a");
  14. }
  15. //当异步委托结束后,把该委托返回的值回传给str
  16. string str1 = testMethod.EndInvoke(result);
  17. Console.WriteLine(str1);
  18. Console.ReadKey();
  19. }
  20. }
  21. //测试类
  22. class TextClass
  23. {
  24. //用来异步
  25. public string asynMethod(int time)
  26. {
  27. Console.WriteLine("启动异步方法");
  28. Thread.Sleep(time);
  29. Console.WriteLine("b");
  30. Console.WriteLine("结束异步方法");
  31. return "异步返回";
  32. }
  33. }

结果

(3)异步调用完成时执行回调方法

winfrom

  1. public partial class Form1 : Form
  2. {
  3. public Form1()
  4. {
  5. InitializeComponent();
  6. //是否捕获对错误线程的调用
  7. Control.CheckForIllegalCrossThreadCalls = false;
  8. }
  9. //
  10. private delegate string delegatehWeb();
  11. delegatehWeb delWeb=new delegatehWeb(webReuest);
  12. private void button1_Click(object sender, EventArgs e)
  13. {
  14. //执行异步,异步结束后,执行Callback方法
  15. IAsyncResult result = delWeb.BeginInvoke(Callback, null);
  16. textBox1.Text = "HTML代码";
  17. }
  18.  
  19. //回调方法
  20. public void Callback(IAsyncResult result)
  21. {
  22. string str = delWeb.EndInvoke(result);
  23. textBox1.Text = str;
  24. //MessageBox.Show(str);
  25. }
  26.  
  27. //获取网站HTML
  28. public static string webReuest()
  29. {
  30. HttpWebRequest httpWebRequest = WebRequest.CreateHttp("http://www.baidu.com/");
  31. WebResponse httpWebResponse = httpWebRequest.GetResponse();
  32. //返回数据流
  33. Stream stream = httpWebResponse.GetResponseStream();
  34. Encoding encode = Encoding.GetEncoding("utf-8");
  35. StreamReader readStream = new StreamReader(stream, encode);
  36. //把流转成字符串
  37. string htmlStr = readStream.ReadToEnd();
  38. Thread.Sleep();
  39. return htmlStr;
  40. }
  41. }

task 执行异步任务, t.Wait()阻塞所在线程

  1. private void button1_Click(object sender, EventArgs e)
  2. {
  3. Task t = Task.Run(() => {
  4. Thread.Sleep(3000);
              //所在线程id
  5. MessageBox.Show(Convert.ToString(Thread.CurrentThread.ManagedThreadId));
  6. });
  7. MessageBox.Show(Convert.ToString(Thread.CurrentThread.ManagedThreadId));
  8. //等待task完成后向后执行
  9. t.Wait();
  10. MessageBox.Show(Convert.ToString(Thread.CurrentThread.ManagedThreadId));
  11. }

(41)C#异步编程的更多相关文章

  1. [C#] 走进异步编程的世界 - 剖析异步方法(下)

    走进异步编程的世界 - 剖析异步方法(下) 序 感谢大家的支持,这是昨天发布<走进异步编程的世界 - 剖析异步方法(上)>的补充篇. 目录 异常处理 在调用方法中同步等待任务 在异步方法中 ...

  2. [C#] 走进异步编程的世界 - 在 GUI 中执行异步操作

    走进异步编程的世界 - 在 GUI 中执行异步操作 [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5877042.html 序 这是继<开始接 ...

  3. JavaScript异步编程的主要解决方案—对不起,我和你不在同一个频率上

    众所周知(这也忒夸张了吧?),Javascript通过事件驱动机制,在单线程模型下,以异步的形式来实现非阻塞的IO操作.这种模式使得JavaScript在处理事务时非常高效,但这带来了很多问题,比如异 ...

  4. 走进异步编程的世界 - 开始接触 async/await

    [C#] 走进异步编程的世界 - 开始接触 async/await   走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async ...

  5. 异步编程 z

    走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $&qu ...

  6. [C#] 走进异步编程的世界 - 开始接触 async/await(转)

    原文链接:http://www.cnblogs.com/liqingwen/p/5831951.html 走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 ...

  7. 利用python yielding创建协程将异步编程同步化

    转自:http://www.jackyshen.com/2015/05/21/async-operations-in-form-of-sync-programming-with-python-yiel ...

  8. 异步编程和线程的使用(.NET 4.5 )

    C#:异步编程和线程的使用(.NET 4.5 )   异步编程和线程处理是并发或并行编程非常重要的功能特征.为了实现异步编程,可使用线程也可以不用.将异步与线程同时讲,将有助于我们更好的理解它们的特征 ...

  9. 走进异步编程的世界 - 开始接触 async/await(转)

    序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $"" 来拼接字符串,相当于string.Fo ...

随机推荐

  1. Linux中nginx的常见指令

    1.启动cd /usr/local/nginxsbin/nginx 版权声明:本文为博主原创文章,未经博主允许不得转载. 原文地址: https://www.cnblogs.com/poterliu/ ...

  2. python-函数的对象、函数嵌套、名称空间和作用域

    目录 函数的对象 函数对象的四大功能 引用 当做参数传给一个函数 可以当做函数的返回值 可以当做容器类型的元素 函数的嵌套 函数的嵌套定义 函数的嵌套调用 名称空间与作用域 名称空间 内置名称空间 全 ...

  3. Python中的属性访问与描述符

    Python中的属性访问与描述符 请给作者点赞--> 原文链接 在Python中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象foo,它有一个nam ...

  4. 【原创】关于高版本poi autoSizeColumn方法异常的情况

    之前使用的3.9版本,autoSizeColumn方法一切正常,现在切换到了3.15版本这个方法就出先了问题,问题如下,无法自动追踪所有的列. Exception in thread "ma ...

  5. src与href的区别

    href: 是指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,用于超链接. src:是指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置:在请求src资源时会将其 ...

  6. Selenium WebDriver- 显式等待

    推荐使用显示等待,元素出现就不会等待而继续执行了.节省时间. #encoding=utf-8 import unittest import time from selenium import webd ...

  7. Leetcode33--->Search in Rotated Sorted Array(在旋转数组中找出给定的target值的位置)

    题目: 给定一个旋转数组,但是你不知道旋转位置,在旋转数组中找出给定target值出现的位置:你可以假设在数组中没有重复值出现 举例: (i.e., 0 1 2 4 5 6 7 might becom ...

  8. day01_12.字符串

    1.字符转义 在字符串中,出现一些比较特殊的字符,容易引起歧义 我们需要转义这些引起歧义的字符串 <?php $a = 'ab\\c'; //转义字符2个 \' \\ $b = 'ab\'c'; ...

  9. Leetcode 435.无重叠区间

    无重叠区间 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠. 注意: 可以认为区间的终点总是大于它的起点. 区间 [1,2] 和 [2,3] 的边界相互"接触" ...

  10. HAZU校赛 Problem K: Deadline

    Problem K: Deadline Time Limit: 2 Sec Memory Limit: 1280 MB Submit: 1106 Solved: 117 [Submit][Status ...