C#的 Task,Thread,ThreadPool 之间有啥异同

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#的 Task,Thread,ThreadPool 之间有啥异同相关的知识,希望对你有一定的参考价值。

你这个问题比较大。

首先说Thread、ThreadPool

    前台线程:主程序必须等待线程执行完毕后才可退出程序。Thread默认为前台线程,也可以设置为后台线程

    后台线程:主程序执行完毕后就退出,不管线程是否执行完毕。ThreadPool默认为后台线程

    线程消耗:开启一个新线程,线程不做任何操作,都要消耗1M左右的内存

    ThreadPool为线程池,其目的就是为了减少开启新线程的消耗(使用线程池中的空闲线程,不必再开启新线程),以及统一管理线程(线程池中的线程执行完毕后,回归到线程池中,等待新任务)

    总结:ThreadPool性能会好于Thread,但是ThreadPool与Thread对线程的控制都不是很够,例如线程等待(线程执行一段时间无响应后,直接停止线程,释放资源,两者都没有直接的API,只能通过硬编码实现)。同时ThreadPool使用的是线程池全局队列,全局队列中的线程,依旧会存在竞争共享资源的情况,从而影响性能。


下面说Task

    Task背后的实现,也是使用的是线程池线程。但是它的性能优于ThreadPool,因为它使用的不是线程池的全局队列,而是使用的是本地队列。是的线程之间竞争资源的情况减少。

    Task提供了丰富的API,开发者可对Task进行多种管理,控制。


详情可以参考我的博客:http://www.cnblogs.com/color-wolf/p/4850869.html

也可以参考:CLR via C#(第4版)

参考技术A task是任务,tread是线程,threadpool是线程池,你直接搜这三个名词就能给你解释。相关文章多的是。
copy一份给你:
Thread就是Thread,需要自己调度,适合长跑型的操作。

ThreadPool是Thread基础上的一个线程池,目的是减少频繁创建线程的开销。线程很贵,要开新的stack,要增加CPU上下文切换,所以ThreadPool适合频繁、短期执行的小操作。调度算法是自适应的,会根据程序执行的模式调整配置,通常不需要自己调度线程。另外分为Worker和IO两个池。IO线程对应Native的overlapped io,Win下利用IO完成端口实现非阻塞IO。

Task或者说TPL是一个更上层的封装,NB之处在于continuation。continuation的意义在于:高性能的程序通常都是跑在IO边界或者UI事件的边界上的,TPL的continuation可以更方便的写这种高scalability的代码。Task会根据一些flag,比如是不是long-running来决定底层用Thread还是ThreadPool,另外也做了些细节优化,比如同一个线程跑好几个Task,比如continuation时根据情况让CPU空转几毫秒来等待前置Task结束,都是为了减少CPU上下文切换。

结论:能用Task就用Task,底下都是用的Thread或者ThreadPool。但是要注意细节,比如告诉Task是不是long-running;比如尽量别Wait;再比如IO之后的continuation要尽快结束然后把线程还回去,有事开个Worker做,要不然会影响后面的IO,等等。

作者:权然
链接:http://www.zhihu.com/question/24911536/answer/50534592
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

C# Task总结(异步操作+并行)

任务Task与线程Thread不可比。Task是为了利用多CPU多核的机制而将一个大任务不断分解成小任务,这些任务具体由哪一个线程或当前线程执行由OS来决定。如果你想自己控制由哪一个Thread执行,要么自己定议task的scheduling, 要么自己来创建Thread来执行代码。

1)task是根据自己需要调用线程

2)thread就是个基本单位

简单地du说,thread是单核多线程,task是多核多线程

 /// <summary>
 /// 简单的task创建方式演示
 /// </summary>
 private static void TaskCreatFun()
 {
     // 其一、通过传统的 new 方式来实例化一个task对象,这种方式需要手动通过start来启动
     Task newTask = new Task(() =>
     {
         Thread.Sleep(1000);
         Console.WriteLine($"Hello Engineer, 我是 new 的一个task,线程ID:Thread.CurrentThread.ManagedThreadId}");
     });

     // 启动 tsak
     newTask.Start();

     // 其二、通过工厂 factory 来生成一个task对象,并自启动
     Task factoryTask = Task.Factory.StartNew(() =>
     {
         Thread.Sleep(1000);
         Console.WriteLine($"Hello Engineer, 我是 factory 生产 的一个task,线程ID:Thread.CurrentThread.ManagedThreadId}");
     });

     // 其三、通过 Task.Run(Action action) 来创建一个自启动task
     Task runTask = Task.Run(() =>
     {
         Thread.Sleep(1000);
         Console.WriteLine($"Hello Engineer, 我是 Task.Run 创建一个自启动task,线程ID:Thread.CurrentThread.ManagedThreadId}");
     });
     runTask.RunSynchronously();

     Console.WriteLine($"Hello Engineer, 我是主线程啦!线程ID{Thread.CurrentThread.ManagedThreadId}");
 }

  Task回调

  a.某一个任务结束回调

 taskList.Add(taskFactory.StartNew(() => this.DoSomethingLong("btnTask_Click_002")));
 taskList.Add(taskFactory.StartNew(() => this.DoSomethingLong("btnTask_Click_001")));
 //回调ContinueWhenAny没有那么精准,不一定是在某个线程完成之后发生
 taskList.Add(taskFactory.ContinueWhenAny(taskList.ToArray(), t =>      Console.WriteLine($"ContinueWhenAny {Thread.CurrentThread.ManagedThreadId.ToString("00")}")));

  b.所有任务结束回调

taskList.Add(taskFactory.ContinueWhenAll(taskList.ToArray(), tList => Console.WriteLine($"这里是ContinueWhenAll {Thread.CurrentThread.ManagedThreadId.ToString("00")}")));

  c.单个任务结束回调

Task task2 = taskFactory.StartNew(t => this.DoSomethingLong("btnTask_Click_005"), "煎饼果子").ContinueWith(t => Console.WriteLine($"这里是{t.AsyncState}的回调"));

  Task等待

Task.WaitAny(taskList.ToArray());//卡界面

Task.WaitAll(taskList.ToArray());//卡界面

  Task获取返回结果

Task<int> intTask = taskFactory.StartNew(() => 123);
int iResult = intTask.Result;
Task<string> intTask = taskFactory.StartNew(() => "123");
int iResult = intTask.Result;

  Task同步执行

可以用task.RunSynchronously() 来同步执行,但是这种方式执行,只有通过new 实例化的task才有效,原因也很简单,其他两种方式创建task都已经自启动执行了,不可能在来一个同步启动执行吧。

也可以通过task.wait()来变相的实现同步执行效果,当然也可以用task.Result来变现的实现,原理很简单,因为wait()和Result都是要阻塞主流程,直到task执行完毕

 

以上是关于C#的 Task,Thread,ThreadPool 之间有啥异同的主要内容,如果未能解决你的问题,请参考以下文章

改善C#程序的建议9:使用Task代替ThreadPool和Thread

为啥我的 C# 代码在回调到 C++ COM 时会停止,直到 Task.Wait/Thread.Join?

C#中 Thread,Task,Async/Await,IAsyncResult 的那些事儿!

小白终于弄懂了:c#从async/await到Task再到Thread

C# Task.Delay()和Thread.Sleep()有什么区别?

C#关于在返回值为Task方法中使用Thread.Sleep引发的思考