async 与 Thread 的错误结合
在 TAP 出现之前,我们可以通过 Thread 来完成一些线程操作,从而实现多线程和异步操作。在 TAP 出现之后,有时候为了更高精度的控制线程,我们还是会使用到 Thread 。文本讲介绍一种错误的使用方式,作为读者的一个参考。
和 TaskCreateOptions.LongRunning 类似
不应该尝试使用 Thread 执行类似的异步操作。因为这浪费了开启线程的花销。
有的时候,你可能会这么写:
var thread = new Thread(async () =>
{
while (true)
{
// do something
await Task.Delay(1000);
}
}){
IsBackground = true
};
thread.Start();
但其实,这是个错误的写法。
IDE 提示
和 TaskCreateOptions.LongRunning 略有不同,采用这种写法,IDE 会给出一个提示,表明希望取消 async 关键字。因为实际上
- Thread 的所有重载中并没有支持 Task 相关的重载。
- async void 除了在 event handler 中使用,其他地方都是不推荐的。
所以这种做法实际上并不推荐。
而 TaskFactory.StartNew() 的重载中,由于存在一个 Func<T> 的重载,所以导致虽然这种这种使用方式错误,却被 IDE 所接受。
所以这里其实就可以总结一个简单的规则:当考察一组 API 是否原生支持 TAP 操作的时候,应该查看这组 API 中是否存在 Task 相关的重载。如果没有,那么说明原生并不能良好支持,如果使用则可能会出现意外的情况
同样的,当我们自己在设计 API 的时候也应该参考该原则,对于自己希望支持 TAP 的 API,应该提供 Task 相关的重载。
昙花线程
在 thread async void 其实上只是一个很小的问题。这个错误的关键还是造成了一个昙花线程。
我们通过以下代码来验证:
var thread = new Thread(async () =>
{
while (true)
{
// do something
await Task.Delay(1000);
}
}){
IsBackground = true
};
thread.Start();
Thread.Sleep(3000);
Console.WriteLine("thread is alive: " + thread.IsAlive);
// thread is alive: False
这里我们可以看到,thread.IsAlive 的值为 False。这是因为,我们在 thread 中使用了 await 关键字,在 await 之后的代码,实际上是在另一个 ThreadPool 中的线程中执行的。而我们的 thread 本身在 await 之后就已经结束了。于是我们就得到了一个昙花一现的线程。
而这种昙花线程无疑就是一种浪费。
如何观测线程的生命周期
其实大体的内容我们已经讲完了。但为了凑一下篇幅,我们着重演示一下如何使用 Rider 来观测线程的生命周期。
首先我们在 Rider 中创建一个单元测试项目,然后在其中创建一个单元测试:
[Test]
public void Test1()
{
var t1 = new Thread(async () =>
{
while (true)
{
// do something
await Task.Delay(1000);
}
})
{
IsBackground = true,
Name = "t1"
};
t1.Start();
var t2 = new Thread(() =>
{
while (true)
{
// do something
Thread.Sleep(1000);
}
})
{
IsBackground = true,
Name = "t2"
};
t2.Start();
Thread.Sleep(3000);
}
然后我们在 Rider 中按照下图选择 Profile 选项:

然后选择 Profile Unit Tests 选项:

稍等片刻之后,我们就可以双击下图中的报告,来查看线程的生命周期:

在查看界面中,我们可以通过线程下来框来查看线程运行所花费的时间:

如果上图,我们可以很直接的看到,t1 线程的生命周期可以说是瞬间就结束了,因为第一次 await 之后,线程就结束了。
总结
在本文中,我们演示了一种错误的使用方式,以及如何使用 Rider 来观测线程的生命周期。
参考
感谢阅读,如果觉得本文有用,不妨点击推荐或者在评论区留下 Mark,让更多的人可以看到。
欢迎关注作者的微信公众号“newbe技术专栏”,获取更多技术内容。
- 本文作者: newbe36524
- 本文链接: https://www.newbe.pro/Others/0x027-This-is-the-wrong-way-to-use-LongRunnigTask-in-csharp/
- 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
https://www.cnblogs.com/eventhorizon/p/15912383.html
https://threads.whuanle.cn/3.task/
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcreationoptions?view=net-7.0&WT.mc_id=DX-MVP-5003606
async 与 Thread 的错误结合的更多相关文章
- Await Async和Thread.waitAll想法?未完待续
[管理员]四九-李冰-修行者(2216529884) 2017/7/3 17:15:12 看着就可以了,这种东西是有使用场景的.并不是你用了就一定有提升的 [管理员]上海-xx科技(lovepoint ...
- 水火难容:同步方法调用async方法引发的ASP.NET应用程序崩溃
之前只知道在同步方法中调用异步(async)方法时,如果用.Result等待调用结果,会造成线程死锁(deadlock).自己也吃过这个苦头,详见等到花儿也谢了的await. 昨天一个偶然的情况,造成 ...
- 为什么我们要使用Async、Await关键字
前不久,在工作中由于默认(xihuan)使用Async.Await关键字受到了很多质问,所以由此引发这篇博文“为什么我们要用Async/Await关键字”,请听下面分解: Async/Await关键字 ...
- Spring及SpringBoot @Async配置步骤及注意事项
前言 最近在做一个用户反馈的功能,就是当用户反馈意见或建议后服务端将意见保存然后发邮件给相关模块的开发者.考虑发邮件耗时的情况所以我想用异步的方法去执行,于是就开始研究Spring的@Async了.但 ...
- 【Thread】java线程之对象锁、类锁、线程安全
说明: 1.个人技术也不咋滴.也没在项目中写过线程,以下全是根据自己的理解写的.所以,仅供参考及希望指出不同的观点. 2.其实想把代码的github贴出来,但还是推荐在初学的您多亲自写一下,就没贴出来 ...
- Hibernate4 No Session found for current thread原因
Hibernate4 与 spring3 集成之后, 如果在取得session 的地方使用了getCurrentSession, 可能会报一个错:“No Session found for curre ...
- (一)Nodejs - 框架类库 - Nodejs异步流程控制Async
简介 Async是一个流程控制工具包,提供了直接而强大的异步功能 应用场景 业务流程逻辑复杂,适应异步编程,减少回调的嵌套 安装 npm insatll async 函数介绍 Collections ...
- Async/Await替代Promise的6个理由
译者按: Node.js的异步编程方式有效提高了应用性能:然而回调地狱却让人望而生畏,Promise让我们告别回调函数,写出更优雅的异步代码:在实践过程中,却发现Promise并不完美:技术进步是无止 ...
- Oracle中建库时报Exception in thread main
Linux操作系统上安装oracle 10g,在启动dbca的时候报 Exception in thread "main" 错误,详细内容如下: [oracle@centos ~] ...
- [转] Async/Await替代Promise的6个理由
Node.js 7.6已经支持async/await了,如果你还没有试过,这篇博客将告诉你为什么要用它. Async/Await简介 对于从未听说过async/await的朋友,下面是简介: asyn ...
随机推荐
- 【JVM】学习JVM垃圾回收理论
参考链接:https://www.cnblogs.com/aspirant/p/8662690.html 一,垃圾回收算法 JVM内存结构:程序计数器.虚拟机栈.本地方法栈.堆区.方法区 1,引用计数 ...
- c语言中位运算符及用法 异或
a&b: 00000000 00000000 a&b=0x0 a|b : 00000000 01011111 a|b=0x5f a^b : 00000000 01011111 ...
- 命令提示符怎么打开和Dos命令的基本使用
Dos命令 Dos命令窗口我们可以通过win+R输入cmd来打开 如果要用管理员身份打开直接在开始里搜索命令提示符,以管理员身份打开! 一些简单的Dos命令 //切换盘符 盘符名: //进入 cd / ...
- Selenium+Python上传文件方法大全
转自:https://www.jianshu.com/p/fba37cc5d5e2
- python学习(day4)
1.selenium库 import selenium #使用selenium跳过登陆 '''selenium pip install selenium ''' from selenium impor ...
- c++ 在项目中创建DLL,并调用
创建DLL分为两种方法,先介绍第一种 一.创建DLL (1) // dll.h #pragma once //dll.h #ifndef DLL_H_ #define DLL_H_ void prin ...
- 通过Linux的socket套接字实现客户端与服务器端的通信
具体案例:使用树莓派ds18b20温度传感器实现温度上报 首先需要获得传感器文件中保存的温度信息: 温度信息通常保存在路径为"/sys/bus/w1/devices/28-xxxxxxxxx ...
- 3月2号Android开发学习
(2)视图基础 1.设置视图的高度 视图宽度通过属性Android:layout_width表达,视图高度通过属性android:layout_heigth表达,宽高的取值主要有以下三种 1.matc ...
- JSP和servlet之间的相互传值
1.从一个jsp页面跳转到另一个jsp页面时的参数传递 (1)使用request对象获取客户端提交的信息 login.jsp页面代码如下: 点击查看代码 <%@ page language=&q ...
- maya灯光导入houdini插件开发
加入工作室时师兄给了两道测试题,由于第一道是完善师兄的一个houdini项目管理插件,我只是开发了一些小功能,所以不好意思拿出来. 第二道题就完全是由自己开发的一个小插件,功能是把maya里的灯光导入 ...
