这个贴开始在C++那边论坛发过,但没几个讨论的,不知道是不是我描述太烂了.
对于这个问题我一直是很有兴趣的(因为工作也是服务器上的应用,我较少做界面,用户交互应用),但是到现在我也没有找到很好的书来看.都是凭借自己的经验.
现在再在我们C#区发一下,我们这区够热度了.讨论的命题:
程序把CPU拖到90%左右是否就是达到了完美效率讨论这个前提肯定是排除垃圾消耗的代码,比如频繁启动新线程做无谓的运算。或无意义的消耗CPU时间。只指有效代码。比如操作一个int[] 有1000万个元素。读出来,然后做 1 个耗时1秒的操作(我们就把这个操作想成是数据库操作或者是socket send操作;每个元素耗时1秒)。如果不做多线程操作,显然我们就得消耗 1000万秒。这个时候运行这个单线程程
序CPU的消耗可能3%不到。但基本你的任务已经无法完成。
那么这样:我可以启动 10个线程,各自分配给他们各自要操作的索引段 如:0-100万,100万-200万 等等这样int[]虽然是全局变量,但不用锁他。 然后10个线程各自工作。 这还是需要100万秒。
int[] 1000万数据 这个东西本身读取肯定是不需要消耗太多CPU的。 消耗时间的是后面的 操作。 而这个操作可能又有干耗以及实耗(抱歉,我就按这样形容了,干耗是指阻塞,不干活等待数据响应等等,而实耗指的是确切需要消耗CPU的动作。我后面也会以这样的认知去描述下面的问题)如果是实耗的话,我们没有办法避免。如果是单核心CPU你起10个线程和起1个线程都需要消耗X时间。而10个线程可能需要消耗更多时间,可能是X+Y 不过Y值很微小罢了。所以,我们多线程就是为了化干耗为0。所以理论上如果你达到化干耗为0,并且你这个程序持续工作X秒的话。 那么这X秒内CPU的占用率应该就会达到90%以上.
如果按我以上描述的去理解.那么下面这2个观点就是错误的.比如:线程并非越多越好. -- 这个显然错误(或者说他是不分青红皂白的,不讲前提条件的).因为只要CPU还存在干耗的话,那么再创建1个线程肯定是更优化的选择(当然,也会有其他类似非阻塞而不加线程的更优选择)这个是非常显而易见的.比如现在你10个线程在操作 1000万数据. 每个线程要消耗1秒.而这1秒里有500毫秒是在阻塞.那么你启动10个线程显然是为了在你某些线程阻塞500毫秒的时候还有其他线程在继续工作.
但是!显然你并不能保证0干耗.这个时候如果10个线程的运算间隙都有 阻塞在干耗的话,能够显著提升效率的其中1个方案就是:再启动一个线程.线程开启数量应该是CPU核心数+1 比如双核CPU就 可以开3个线程可以达到最高效率.这个显然是不完整的描述.(也就是错误的). 因为 如果你的程序干耗多的话,那么显然就和是否多核无关. 如果是实耗可能双核CPU开3个线程可以达到最高效率
关于线程数=CPU核心数+1 这个问题,我想大部分中级程序员都会对这个东西发窘,我开始也是不明所以,不知道这是讲的什么,只感觉这个东西在混淆视听.
而实际上,这个也很简单:也就是干耗为0的情况下(近似于0)如果你的CPU是多核的.那么请你不要再用单线程进行工作,而应该采取CPU核心数+1 的方案.-------------------------------------还谈谈c#的线程池与java的线程池.(这2个语言的线程池应该是近似用途与逻辑吧)
我对这个东西接触都不多,但从目测效率上感觉:这个东西的确没什么大的用处.在你需要高效运行的程序的时候最好是不要去用语言级别的线程池,因为总是感觉这个东西不是为了提高效率而设置的.具体是为什么场景设计的我也不知道(知道的可以说一说).反正提高效率尽量自己new线程,然后统一自己管理.总结一下,多线程按本质来讲,我认为就是降低干耗,充分利用阻塞时间做其他事情.而从实际应用来讲可能有时候是:错开系统瓶颈,比如一个程序有数据库操作的话不要写成1串串下来的程序,而应该在写数据库操作的时候把线程分割开.而多线程用到现在其实最麻烦也最难的是共享数据的线程安全.以及同步/效率的问题.这贴用来讨论,欢迎拍砖,免得我一直脑袋里装错误看法最后,第1次发200分的贴,不知不觉可以发200分的贴了,庆祝一下.

解决方案 »

  1.   

    你对线程的理解存在一些问题:对于单CPU的机器来说,多线程对于大量数据的运算毫无益处,反而在线程调度上浪费时间,比如你这一段:比如操作一个int[] 有1000万个元素。读出来,然后做 1 个耗时1秒的操作(我们就把这个操作想成是数据库操作或者是socket send操作;每个元素耗时1秒)。如果不做多线程操作,显然我们就得消耗 1000万秒。这个时候运行这个单线程程
    序CPU的消耗可能3%不到。但基本你的任务已经无法完成。
    那么这样:我可以启动 10个线程,各自分配给他们各自要操作的索引段 如:0-100万,100万-200万 等等这样int[]虽然是全局变量,但不用锁他。 然后10个线程各自工作。 这还是需要100万秒。对于单CPU机器来说,这是不可能发生的,微观时间内,每个时刻只能一个线程在运行。
    即使对于多CPU机器来说,使用多线程能提高效率,也远不会是你描述的这样:10个线程同时工作,你有几个CPU或几个核心?
      

  2.   

    单CPU机器,多线程运用在不同性质的若干工作上,比如一个读数据库,一个网络收发,一个界面更新,这是合理的,同一性质的工作,尤其是可能会阻塞的工作,多线程经常被滥用。
      

  3.   

    线程并非越多越好,这是正确的,不管你是否运用多线程,大多数情况下,CPU仍然是空闲的时间居多,因为程序需要处理其他事情而非进行数据运算。线程数=CPU核心数+1,这个倒是未必,看线程如何运用了。
      

  4.   


    1个send 是有 [等待] 时间的.这个[等待]正在发生的时候, CPU是0消耗的.  而[等待]正是我下面所描述的 [干耗],或者叫阻塞或者叫进程休眠.这个恐怕不是我的理解问题.
      

  5.   

    而多线程的目的正是在于: 在你[等待]发生的时刻,我下一个线程立即抢占CPU资源,达到不让CPU休息的目的.而事实也证明CPU的确不需要休息.
      

  6.   

    听说高手编程用CPU,小菜编程用内存
      

  7.   

    程序把CPU拖到90%左右是否就是达到了完美效率
    ----------------------------------------
    这个不好说: 严格的说系统的多线程目的是节约 存储器的使用率,把一部分压力 转换到cup 那里去,
    也就是所谓的压榨cup。但是做activeX开发时 又冲突了。 
      

  8.   

    6楼说的非常正确,多线程不是这样用的。如果你仅仅是为了抢占cpu,那么将进程优先级提高就好了。(当然,从某些角度来说,提高优先级也只是饮鸩止渴。)多线程可以提高效率只是在于一些不占用cpu的I/O操作,例如等待网络的数据包返回,等待串口的数据发送完毕,等待磁盘写入完成,等等之类。类似于我们平时说的,利用工作调度提高整体工作效率。
      

  9.   


    这个问题的话.
    呵呵  我说100个线程 是有点过火了. 但我是举了个例子,不太恰当.不过 ,10个线程进行send 倒是很常见.大的网络应用里面 带宽是很恐怖的.
    并且大的网络应用里面 server端得处理能力也是很恐怖的...
      

  10.   

    这个问题的话.
    呵呵 我说100个线程 是有点过火了. 但我是举了个例子,不太恰当.
    -----------------------------------------------
    我是否可以认为,你还是承认了,线程不是越多越好?
    而且,如果是做同一性质的工作,线程数目的确不应该超过CPU核心数+1,拿这个例子来说,不论瓶颈在CPU还是在网络接口,更多线程都是无意义的,如果是没有瓶颈的理想状态,那么CPU也已经达到或接近满负荷了。再说一点,线程调度的代价远比你想象的要大,因为这涉及到核心态和用户态的切换。
      

  11.   

    什么时候用多线程??
    1.用户界面需要.
    2.性能瓶颈不在cup的时候,就可以用多线程.  特别涉及到网络发送接收.我曾经用20~40个线程下载网站数据,整个程序就像一个下载器一样.只用一个线程来处理下载下来的数据.cpu也才最多70%.我用的还是 p4 单核的.但是网络就撑的满满的. 没办法客户说一定要快.现在做到不怕你电脑有多慢就怕你网络不够快.
    有人说我用那多多线程浪费cpu资源.我说那也没办法.为了实现客户的要求的快.我必须牺牲以一点cpu资源来挤爆客户的网络.呵呵. 看应用来决定是否选择多线程.
      

  12.   

    我曾经用20~40个线程下载网站数据,整个程序就像一个下载器一样.只用一个线程来处理下载下来的数据.cpu也才最多70%.我用的还是 p4 单核的.但是网络就撑的满满的. 没办法客户说一定要快.现在做到不怕你电脑有多慢就怕你网络不够快.
    有人说我用那多多线程浪费cpu资源.我说那也没办法.为了实现客户的要求的快.我必须牺牲以一点cpu资源来挤爆客户的网络.呵呵.  
    ---------------------------------这样的做法是对使用同一服务器的其他客户的不公平,服务器总是尽可能公平地对待每个连接,你一个客户消耗20~40个连接,其他客户不用活了。
    我对局域网中使用X雷的行为是深痛恶绝(当然,X雷的可恶之处不仅仅是使用多线程)。
      

  13.   

    这个结论很奇怪.如果不允许使用非阻塞模型来写httpserver
    那么你建立一个Http server 单线程...一个用户的请求处理完成之前下个请求完全等待....  如果这个用户需要查询一个 1000万数据的表,耗时10秒.那么....如你所说,如果我这个还是分布式,还部署在多核心的PC SERVER上.莫非就真如你所所应该按 '单线程' 来写了?
      

  14.   

    同意,cpu[单核]一个时间段内只能处理一个任务,多线程只是频繁切换,轮流占用时间片而已.
      

  15.   


    现在的社会,我看不到有多少人会考虑其他人会怎么样,所以X雷和PPS之类的盛行。
    远了远了,不扯了...
      

  16.   

    lai  xue  xi de  
      

  17.   

    好火,我也来讲讲。个人在工作中用到了一些多线程的东西,主要在:
    1,界面交互响应:以避免假死、无响应状态
    2,socket通信的接受和发送端,这是为了提高效率个人认为多线程的目的主要在于并发,就是并行运行一些程序,而不是简单的提高程序效率,相反,有时候多线程的程序反而比单线程的效率低。再就是线程个数问题,我觉得这是应该是随场景环境而定的,超过不超过CPU数+1不重要。
      

  18.   

    多线程,主要是想提高程序的可伸缩性。例如,有很多任务需要并行进行,那么可能需要多线程。
    多线程实际上是一个假象,就是说,因为CPU的时间总是有限的,那么CPU需要频繁地切换,在某个时间执行某个线程的任务。这种情况,如果用的不好,反而增加了CPU的负担,降低了系统性能
    VS2010中提供了多CPU操作
    Task Parallel Library(TPL)和Coordination Data Structures 
      

  19.   

    CPU虽然是一个,但是使用多线程可以非常好的安排线程的优先级,把任务分为轻重缓急分别对待。占时少且重要的就给一个高优先级,这样可以随时打断低优先级的任务,它用完了CPU又可以立即返回给低优先级的任务使用。我原来编写视频播放程序时,把音频的解压和音视频的同步各用一个线程,优先级高。视频解压程序用一个低优先级的线程,他最耗时,时间来不及就不显示某些帧。但是声音断续问题更严重。
      

  20.   

    我感觉多线程之妙,不在于原理,而在于动手实践
    dotnet多线程,初学者一般推荐使用:backgroudwork,效率相当不错,特别是继承它之后,使用reportprogress来与线程内部属性交互,可以直接操作UI,确实又傻瓜又简单,然后自己用list做个简单的线程池,外加线程的暂停,线程退出等功能,完全可以用在多线程下载之类的软件上
      

  21.   

    难怪C++论坛没几个讨论的...不是你描述太烂,是你理解根本不正确...使用多线程是为了避免线程阻塞,提高可响应性,改善交互...而不是为了提高CPU效率,事实上提高不了,总计算时间只会多不会少...某些应用的效率提升只是让系统多加班的表面现象...滥用多线程只会降低效率,并可能带来死锁问题...这点芥子讲得够清楚了...“线程并非越多越好”是非常正确的说法...我感觉你的问题源于没有弄明白抢占式多任务操作系统的本质,把多CPU/多核并行处理和多线程混为一谈...你得先明白...多CPU/多核并行处理是硬件级的功能,而多线程仅仅是逻辑级的功能...就好像一个工厂,增加生产线并配置适当数量的工人才能提升生产效率,只是不断增加工人生产效率反而会越来越低...
      

  22.   

    据个人的了解,“线程数并非越多越好”这句话是绝对正确的,增加线程数,当然是为了减少数据等待,这里的数据等待有两种,一种是闲等,一种是忙等,闲等就是某个CPU再等其他CPU释放资源或者等待用户输入数据或命令等,这个时候闲等的CPU瞬间占用率是0的。而忙等就是在占用CPU资源的情况下等待数据,例如CPU等待内存子系统返回数据。但这个时候CPU不能接受其他任务,CPU的瞬间占用率是100的。增加CPU数和线程数可以有效地降低CPU的平均等待时间(平均每个CPU的闲等和忙等的时间总和)。但是对于单个CPU来说,例如在一台单核心单CPU的计算机上,CPU在处理一个线程结束切换到另一个线程,或者一个线程被中止切换到另外一个线程之间,是有一个线程切换的过程,当然线程切换是需要消耗CPU性能的,至于切换的算法,消耗多少CPU性能就看操作系统了。在多线程并行的操作系统中,操作系统会让每个线程进入CPU一小段时间(这段时间叫时间片)。对于当今流行的操作系统(Windows 或 Linux),当系统中需要CPU处理的线程数不断增加,操作系统会相应地缩短每个线程的时间片。换言之,就是在相同时间内系统进行线程切换的次数就多了。这样CPU的效率就显然降低了,几时对于多核心多CPU的计算机也如此。而至于完成一个任务到底开多少线程才是最高效,我觉得要看算法中需要等待的时间和等待的类型,还有多线程之间的关联度。LZ所具体的int[] 1000万个数据,加入对于这1000万个数据的运算之间是存在关联的,例如int[2]的运算需要等待int[1]的结果,这样的话,当然吧int[1]和int[2]放到同一个线程中比较好了,虽然表面上看CPU的利用率(占用率)低了,但这样也许比int[1]int[2]分开两个线程独立运算自己的结果更快。
      

  23.   

    要讨论这个问题,我觉得楼主应该要换角度来看 。 多线程的运用,最主要的目的是 “协作”。是根据需要将程序分为若干段进行执行,在加上同步完成某一只有单线程无法完成的事务。
      多线程并不是用来提高CPU的运算速度。你可以回顾操作系统的发展历史,从单作业系统到多作业系统,是为了充分利用CPU,防止在某线程正在等待其他资源(除CPU)是造成的CPU浪费。只是提高了CPU使用效率,同时满足用户响应需求。
      在单CPU情况下,楼主所说的分为多个线程的做法,不仅不会降低运算时间,同时CPU还得消耗时间去进行线程之间的切换。是得不偿失的。                                                                      ---------
      

  24.   

    要讨论这个问题,我觉得楼主应该要换角度来看 。 多线程的运用,最主要的目的是 “协作”。是根据需要将程序分为若干段进行执行,在加上同步完成某一只有单线程无法完成的事务。
      多线程并不是用来提高CPU的运算速度。你可以回顾操作系统的发展历史,从单作业系统到多作业系统,是为了充分利用CPU,是防止在某线程正在等待其他资源(除CPU)是造成的CPU浪费。提高了CPU使用效率,同时满足用户响应需求。这是另一原因。
      在单CPU情况下,楼主所说的分为多个线程的做法,不仅不会降低运算时间,同时CPU还得消耗时间去进行线程之间的切换。是得不偿失的。                                                                      ---------
      

  25.   

    有明白人线程开启数量应该是CPU核心数+1;     这是狗屁理论
      

  26.   

    线程开启数量应该是 CPU 核心数 + 1这个有一定道理,比如安装 QT 之后,在 make 的时候,如果是双核的机器,加 -j3 指定使用三个线程,能够加快 make 的进程。
      

  27.   

    无论你开多少线程,能同时运行的最多只有CPU核心的个数,开太多线程反而会因为线程调度导致性能下降
    并行计算一般开CPU数或CPU*2的进程.以让CPU所有核心都利用到.
    int[] 100万的数据,在单核机器上开多线程速度会比单线程慢,但是在10个核上,这10个线程是同时运行的,运行时间只有10万秒(实际上因为用同一个内存的原因,时间会远大于10万秒)
      

  28.   

    还是具体情况具体分析吧
    比如一个socket服务端程序,支持多个并发client的访问,如果能够预期到业务量不大的话,那么使用select完全可以满足要求,否则就需要分离多个线程单独处理了。
    但是线程确实也不是越多越好,线程增加本身也会对操作系统的调度产生影响,我的理解线程池的作用就是避免频繁的创建新的线程去处理新的业务,而是尽量用已有的空闲线程来处理。以你的例子来说,1000万个数据,到底要用多少个线程才能使得干耗接近0,我们不知道,但是可以在程序中判断当还存在空闲的时候可以再调用线程池中的一个线程来处理。
      

  29.   

    从理论上讲,多进程和多线程都是伪并发,即是几楼说的:防止在某任务正在等待其他资源(除CPU)而阻塞,提交CPU运行效率,而非速度,因其速度在出厂时就定了。从CPU级来说,是让流水线尽量充满。从这个角度理解,合适的多线程在哪都能提高效率,并不局限于单核多核。