架构师_程序员_码农网

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 23634|回复: 5

[资料] .net/c# Task为什么会比Thread慢?

[复制链接]
发表于 2017-5-3 16:40:28 | 显示全部楼层 |阅读模式
 .NET 4包含新名称空间System.Threading.Tasks,它 包含的类抽象出了线程功能。 在后台使用ThreadPool。 任务表示应完成的某个单元的工作。 这个单元的工作可以在单独的线程中运行,也可以以同步方式启动一个任务,这需要等待主调线程。 使用任务不仅可以获得一个抽象层,还可以对底层线程进行很多控制。
  在安排需要完成的工作时,任务提供了非常大的灵活性。 例如,可 以定义连续的工 作—— 在一个任务完成后该执行什么工作。 这可以区分任务成功与否。 另外,还可以在层次结构中安排任务。例如,父任务可以创建新的子任务。 这可以创建一种依赖关系,这样,取消父任务,也会取消其子任务。


现在都流行用Task执行方法,而且高性能,不知道task性能高在哪里,

我自己测试的Task和Thread,我感觉Task反而很慢,非常影响性能,测试代码如下:

我们循环执行1000次方法,然后,方法里面阻塞100毫秒,测试结果如下:

QQ截图20170503163006.jpg QQ截图20170503163047.jpg

结果:
Thread执行完成,耗时:188毫秒
Task执行完成,耗时:14671毫秒


两者速度相差78倍!!!!

Task非常慢,不知道为什么会出现这种情况,是不是我测试代码有问题,还是什么?希望各位大神能够说明,为什么会出现这种情况。。。




上一篇:使用 ASP.NET Core 发送邮件
下一篇:C#并行计算 Parallel.Foreach&Parallel.For
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
 楼主| 发表于 2020-10-13 10:47:17 | 显示全部楼层
tongli1996218 发表于 2020-10-13 09:34
为保证和Thread一样的代码,我的操作是如下代码, 上面是伪代码
PS:仅仅调用await Task.Delay,而后续不加 ...

可以,thanks

Task执行时间:117.0357

可以修改为如下代码:

Task.Run 代替 Task.Factory.StartNew,因为它会自动解包内部任务。
Task.WaitAll 等待外部任务而不是内部任务。使用 Task.Run 不具有嵌套任务。


查看 msdn 文档,发现 Task.Delay Method 方法会创建一个任务,该任务在指定的毫秒数后完成。(其实会创建一个新的线程,加了 await 等待任务执行完成,不知道我理解的对不对)

https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.delay?view=netcore-3.1

另外 Task vs void 区别

Task 返回异步方法可以等待
void 返回异步方法不能等待,它确实是异步工作的,您无法知道何时完成,无法监控该异步操作的状态。


参考:

https://www.cnblogs.com/0xMe/p/11982974.html
https://blog.csdn.net/huiwuhuiwu/article/details/53590311

总之:代码有问题,我不应该在 Task 方法内用 Thread.Sleep
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
发表于 2020-7-21 13:09:29 | 显示全部楼层
我今天也遇到了同样的问题,使用多线程进行AES加密,Task比Thread慢了好多!!!
请问楼主找到原因了吗
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
发表于 2020-10-12 19:24:48 | 显示全部楼层
本帖最后由 tongli1996218 于 2020-10-12 19:43 编辑

经过测试楼主的代码,当程序启动后,多次运行,Task的时间会持续减少,在我的电脑上会减少到比Thread还要少的地步,而Thread则是稳定在这个时间内。

后发现是Thread.Sleep(100)方法对Task有负面影响,而对Thread没有,可以将Thread.Sleep(100)换成数字自加或await Task.Delay(100)等其他耗时程序验证

PS:Thread.Sleep调用后会结束当前线程切片时间,如Thread.Sleep(0)会将当前线程切片时间结束,并转移至其他线程运行。Task内部是线程池,能优化线程的上下文切换,减少CPU损耗时间(尤其对于多核CPU优化极为明显),而Thread.Sleep(100)会打乱Task原本线程池的切换逻辑,造成大量CPU时间损耗

将 Thread.Sleep(100)换成 await Task.Delay(100)则会发现Task的时间消耗也仅仅100多毫秒,如下所示:
private void TaskTest()
{
        Thread.Sleep(100);
         ...执行操作
}
换成
private async void TaskTest()
{
      await Task.Delay(100);
      ...执行操作,对于Task而言时间消耗100多毫秒,对Thread和原先Thread.Sleep(100)一致
}




码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
 楼主| 发表于 2020-10-12 22:53:05 | 显示全部楼层
tongli1996218 发表于 2020-10-12 19:24
经过测试楼主的代码,当程序启动后,多次运行,Task的时间会持续减少,在我的电脑上会减少到比Thread还要少 ...

我试着改成如下代码:
Task.Delay(100000);

Task执行时间:14.1306 ms,总耗时确实非常短,但是,我发现 Task 调用的方法并没有执行完成。
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
发表于 2020-10-13 09:34:33 | 显示全部楼层
本帖最后由 tongli1996218 于 2020-10-13 09:40 编辑
小渣渣 发表于 2020-10-12 22:53
我试着改成如下代码:
Task.Delay(100000);

为保证和Thread一样的代码,我的操作是如下代码, 上面是伪代码
PS:仅仅调用await Task.Delay,而后续不加上代码,Task开启的线程是即时返回,为保证模拟compute-bound,可以使用for (int a = 0; a< 1000000; ++a){};此类方法代替

private async static void TaskTest()
        {
            await Task.Delay(100000);
             Interlocked.Increment(ref run);    //lock中run++的作用,不过开销更小
            if(run == j)
             {
                stopwatch.Stop(); //  停止监视
                TimeSpan timespan = stopwatch.Elapsed;  //获取当前实例测量得出的总时间
                Console.WriteLine("Task执行时间:" + timespan.TotalMilliseconds); //总毫秒数
              }
        }所消耗的时间也是非常短


码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

免责声明:
码农网所发布的一切软件、编程资料或者文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:help@itsvse.com

QQ|手机版|小黑屋|架构师 ( 鲁ICP备14021824号-2 )|网站地图

GMT+8, 2024-4-20 12:36

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表