博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅析C#中的Thread ThreadPool Task和async/await
阅读量:4358 次
发布时间:2019-06-07

本文共 4069 字,大约阅读时间需要 13 分钟。

.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
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也有种不同的写法:

 

//写法1async  Task  Handle()        {            string re = await OnStartAsync();             //dosth        }//写法2async 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:根本就无法获取正确的返回值,实则没有等待异步执行,而是直接返回了。

 

以上,水平有限,如有不足,敬请指正。如有侵权 请联系作者删除。

转载于:https://www.cnblogs.com/nevermore-wd/p/10565639.html

你可能感兴趣的文章
语言、数据和运算符
查看>>
正则表达式30分钟入门教程
查看>>
sqlserver try catch·
查看>>
怎么在三维世界里叙述五维故事
查看>>
css技巧
查看>>
代码优化(一)
查看>>
为什么JSP会比Beetl慢
查看>>
移动端rem的用法
查看>>
php-laravel中间件使用
查看>>
myslq 表与表之前的数据转移
查看>>
python学习日志
查看>>
微信自媒体账号涉违规大规模被封
查看>>
35.数组中的逆序对
查看>>
HDU 1811 Rank of Tetris
查看>>
绑定 前台
查看>>
由当前日期计算相应的周一和周日
查看>>
Silverlight Excel Release process
查看>>
Python(xlrd、xlwt模块)操作Excel实例(一)
查看>>
ZOJ Monthly, November 2012 - G - Gao The Sequence
查看>>
react dnd demo2
查看>>