浅析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 ...
随机推荐
- Partition Array into Disjoint Intervals LT915
Given an array A, partition it into two (contiguous) subarrays left and right so that: Every element ...
- connect: Address is invalid on local machine or port is not valid on remote
idea 运行正常打成jar包运行提示“connect: Address is invalid on local machine or port is not valid on remote” , 解 ...
- dubbo学习(zz)
dubbo学习 博客分类: 开源软件 Dubbo是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站 ...
- POJ 2433 Landscaping (贪心)
题意:给定一个序列表示一群山,要你保留最多 K 个山峰,最少要削去多少体积和土.一个山峰是指一段连续的相等的区间,并且左边和右边只能比这个区间低,或者是边界. 析:贪心,每次都寻找体积最小的山峰,然后 ...
- attachEvent方法绑定事件
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- (转)php语法(符号用法)
转自:http://blog.unvs.cn/archives/php-equal-bracket.html 学习PHP过程中,会常碰到一些特殊的符号,比如:=.==.===.->.=>. ...
- 20145232 韩文浩 《Java程序设计》第6周学习总结
教材学习内容总结 Java是以串流(Stream)的方式来处理输入与输出. 串流是一种抽象观念,从键盘输入资料,将处理结果输入档案,以及读取档案的内容等动作皆视为串流的处理. 输入串流代表对象为jav ...
- Job Interview: Why Only 3 Questions Really Matter
Even for the most fearless amongst us, job interviews can be nerve wracking. In order to give us the ...
- FatMouse's Speed (hdu 1160)
#include <iostream> #include <cstdio> #include <cstring> #include <algori ...
- Alpha阶段敏捷冲刺(二)
1.提供当天站立式会议照片一张. 2.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 祁泽文:上网了解了艾宾浩斯遗忘曲线算法. 徐璐琳:找交互模块的源 ...