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