浅析C#中的Thread ThreadPool Task和async/await
.net 项目中不可避免地要与线程打交道,目的都是实现异步、并发。从最开始的new Thread()入门,到后来的Task.Run(),如今在使用async/await的时候却有很多疑问。
先来看一段代码:使用Task实现异步
Task.Run(() =>
{
message = (IBytesMessage)consumer.Receive(m_Interval);
});
Receive()方法是一个延迟返回的方法,m_Interval是超时时间。如果采用同步方式执行Receive()的话,那整个程序就会被这个方法堵塞。我个人最习惯的处理方式就用Task.Run()。可惜项目要求必须使用.net framework3.5,所以只能退而求其次,放弃Task,使用Thread或者ThreadPool。
使用Thread实现异步:
new Thread(() =>
{
message = (IBytesMessage)consumer.Receive(m_Interval);
}).Start();
直接new Thread().start()这个写法是很危险的,这里只做参考。在C# 5以后的书籍中,你可能会看到这样一句话:一旦你输入了new Thread(),那就糟糕了,说明项目的代码太过时了。
使用ThreadPool实现异步:
ThreadPool.QueueUserWorkItem(Listen);
private void Listen(object state)
{
message = (IBytesMessage)consumer.Receive(m_Interval);
}
ThreadPool 内部有一套完整的线程管理机制,可以让开发者完全忽略Thread的生命周期控制。但ThreadPool中的线程,都是后台线程,当主线程执行完毕时,程序并不会等待后台线程的执行,而是直接退出。Thread则是前台线程,主程序会等待所有前台线程执行完毕后才会退出。另外在使用ThreadPool的时候需要注意QueueUserWorkItem的参数类型是:
public delegate void WaitCallback(object state) 所以,Listen方法有一个未用到的参数state。
综上,Task还是最优的解决方案。
说到这,问题看似解决了,.net 4.0及以上 Task是不二之选,低版本择优先选择ThreadPool,特殊情况考虑Thread。那么 .net4.5的新特性 async/await 有什么用呢?上述情况需要用到async/await 吗?
这里我们需要看一下完整的代码
private void Listen(object state)
{
message = (IBytesMessage)consumer.Receive(m_Interval);
if (message != null)
{
m_IAsyncMesssgae.OutputMessage(message.ToString());
}
else
{
m_IAsyncMesssgae.OutputException(new Exception("Wait timed out."));
}
}
public void OnStartAsync()
{
try
{
if (m_IsConnected && !m_IsListening)
{
connectionWPM?.Start();
m_IsListening = true;
ThreadPool.QueueUserWorkItem(Listen);
}
}
catch (Exception ex)
{
m_IAsyncMesssgae.OutputException(ex);
}
finally
{
OnStop();
}
}
这里红色字体的m_IAsyncMesssgae是一个回调的接口实例,也就说,此代码中,通过接口回调的方式把Receive()方法延迟返回的message返回给调用者。目前的代码是可以满足需求的。
我们试着用asynv和await实现一下这个需求。
public async void OnStartAsync()
{
if (m_IsConnected && !m_IsListening)
{
connectionWPM?.Start();
m_IsListening = true;
message = await Task.Run(()=> {return (IBytesMessage)consumer.Receive(m_Interval); });
}
}
1)async/await 和刚才说的Thread Task ThreadPool并不是一个概念。前者是控制异步和并发的关键字,后者是对线程的三种实现方式。
2)async/await只能和Task结合使用,async标记的方法 只能有三种返回值Task,Task<T>,void(不建议,因为async/await 就是为了获取异步方法的返回值)。
3)await等待的内容也必须是Task或者Task<T> 上面代码隐藏了一个内容,其实Task.Run()也是一个返回值为Task<T>的方法。
4)await还有一个作用是将Task<T>转成T。
5)在同一个用async标记的方法内,所有在await代码段之后的代码 都要等待await后的内容执行完成后才能执行。
6)如果一个非async方法 调用async方法获取异步返回值,那么就无法成功获取异步返回值。
再把返回值void修改一下:
public async Task<IBytesMessage> OnStartAsync()
{
if (m_IsConnected && !m_IsListening)
{
connectionWPM?.Start();
m_IsListening = true;
message = await Task.Run(()=> {return (IBytesMessage)consumer.Receive(m_Interval); });
}
return message;
}
这样一来,外部调用时候,就不需要接口回调了,直接调用OnStartAsync就可以了。切记!调用OnStartAsync的方法必须也是async,否则就直接返回message的默认值,而不是等待TaskRun()的执行。await只在所属的async方法内奏效。
调用OnStartAsync也有种不同的写法:
//写法1
async Task Handle()
{
string re = await OnStartAsync();
//dosth
}
//写法2
async Task Handle()
{
var re = OnStartAsync();
//dosth
do(await re);
}
//写法3
void Handle()
{
var re = OnStartAsync();
do(re);
}
写法1:dosth需要等待 OnStartAsync执行完毕后再执行。
写法2:dosth先执行,然后再执行do(await re)
写法3:根本就无法获取正确的返回值,实则没有等待异步执行,而是直接返回了。
以上,水平有限,如有不足,敬请指正。如有侵权 请联系作者删除。
浅析C#中的Thread ThreadPool Task和async/await的更多相关文章
- 从Thread,ThreadPool,Task, 到async await 的基本使用方法解读
记得很久以前的一个面试场景: 面试官:说说你对JavaScript闭包的理解吧? 我:嗯,平时都是前端工程师在写JS,我们一般只管写后端代码. 面试官:你是后端程序员啊,好吧,那问问你多线程编程的问题 ...
- Thread,ThreadPool,Task, 到async await 的基本使用方法和理解
很久以前的一个面试场景: 面试官:说说你对JavaScript闭包的理解吧? 我:嗯,平时都是前端工程师在写JS,我们一般只管写后端代码. 面试官:你是后端程序员啊,好吧,那问问你多线程编程的问题吧. ...
- C#中 Thread,Task,Async/Await,IAsyncResult 的那些事儿!
说起异步,Thread,Task,async/await,IAsyncResult 这些东西肯定是绕不开的,今天就来依次聊聊他们 1.线程(Thread) 多线程的意义在于一个应用程序中,有多个执行部 ...
- C#中 Thread,Task,Async/Await,IAsyncResult 的那些事儿![转载]
说起异步,Thread,Task,async/await,IAsyncResult 这些东西肯定是绕不开的,今天就来依次聊聊他们 1.线程(Thread) 多线程的意义在于一个应用程序中,有多个执行部 ...
- 详解C#中 Thread,Task,Async/Await,IAsyncResult的那些事儿
说起异步,Thread,Task,async/await,IAsyncResult 这些东西肯定是绕不开的,今天就来依次聊聊他们 1.线程(Thread) 多线程的意义在于一个应用程序中,有多个执行部 ...
- C#中 Thread,Task,Async/Await 异步编程
什么是异步 同步和异步主要用于修饰方法.当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法:当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调 ...
- Thread,Task,async/await,IAsyncResult
1.线程(Thread) 多线程的意义在于一个应用程序中,有多个执行部分可以同时执行:对于比较耗时的操作(例如io,数据库操作),或者等待响应(如WCF通信)的操作,可以单独开启后台线程来执行,这样主 ...
- thread、Task、async & await
学习 Jesse 的文章 async & await 的前世今生(Updated) 而来 Thread是最开始使用的多线程.new一个Thread对象,将方法传进去.手动Start() 还可以 ...
- c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习
c#中@标志的作用 参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...
随机推荐
- Permutation Sequence LT60
The set [1,2,3,...,n] contains a total of n! unique permutations. By listing and labeling all of the ...
- javase高级技术 - 反射
在说反射之前,必须得先说说java的类加载器,类加载器的定义:将.class文件加载到内在中,并为之生成对应的Class对象. 一般有三种 1 Bootstrap ClassLoader 根类加载器也 ...
- NotificationMangerService处理显示通知
设置——>应用——>点击“已下载”列表中的任一APP,如图: 代码位置:Settings\src\com\android\settings\applications\InstalledA ...
- Mac OS X Git安装教程
http://code.google.com/p/git-osx-installer上也提供了一个Git的图形化客户端:OpenInGitGui,可以从这里获得,OpenInGitGui十分小巧,下载 ...
- 20155312 2006-2007-2 《Java程序设计》第六周学习总结
20155312 2006-2007-2 <Java程序设计>第六周学习总结 课堂笔记 学习进程 周一看视频-2h 周二以代码为中心看书-3h 课后选择题-5h 教材指导 应试 Linux ...
- MySQL查找SQL耗时瓶颈 SHOW profiles
http://blog.csdn.net/k_scott/article/details/8804384 1.首先查看是否开启profiling功能 SHOW VARIABLES LIKE '%pro ...
- day10作业—(闭包迭代器递归)
补充:一个星号的 打散和聚合 a, b , *c = [1,2, 1,4] print( a , b , *c) #1 2 1 4 print(a, b, c) #1 2 [1, 4] *c , = ...
- 用百度AI的OCR文字识别结合JAVA实现了图片的文字识别功能
第一步可定要获取百度的三个东西 要到百度AI网站(http://ai.baidu.com/)去注册 然后获得 -const APP_ID = '请填写你的appid'; -const API_KEY ...
- PHP标准库 SPL
PHP SPL笔记 这几天,我在学习PHP语言中的SPL. 这个东西应该属于PHP中的高级内容,看上去很复杂,但是非常有用,所以我做了长篇笔记.不然记不住,以后要用的时候,还是要从头学起. 由于这是供 ...
- CodeCraft-19 and Codeforces Round #537 (Div. 2) D 多重排列 + 反向01背包 + 离线处理
https://codeforces.com/contest/1111/problem/D 多重排列 + 反向01背包 题意: 给你一个字符串(n<=1e5,n为偶数),有q个询问,每次询问两个 ...