这个贴开始在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分的贴了,庆祝一下.
对于这个问题我一直是很有兴趣的(因为工作也是服务器上的应用,我较少做界面,用户交互应用),但是到现在我也没有找到很好的书来看.都是凭借自己的经验.
现在再在我们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分的贴了,庆祝一下.
序CPU的消耗可能3%不到。但基本你的任务已经无法完成。
那么这样:我可以启动 10个线程,各自分配给他们各自要操作的索引段 如:0-100万,100万-200万 等等这样int[]虽然是全局变量,但不用锁他。 然后10个线程各自工作。 这还是需要100万秒。对于单CPU机器来说,这是不可能发生的,微观时间内,每个时刻只能一个线程在运行。
即使对于多CPU机器来说,使用多线程能提高效率,也远不会是你描述的这样:10个线程同时工作,你有几个CPU或几个核心?
1个send 是有 [等待] 时间的.这个[等待]正在发生的时候, CPU是0消耗的. 而[等待]正是我下面所描述的 [干耗],或者叫阻塞或者叫进程休眠.这个恐怕不是我的理解问题.
----------------------------------------
这个不好说: 严格的说系统的多线程目的是节约 存储器的使用率,把一部分压力 转换到cup 那里去,
也就是所谓的压榨cup。但是做activeX开发时 又冲突了。
这个问题的话.
呵呵 我说100个线程 是有点过火了. 但我是举了个例子,不太恰当.不过 ,10个线程进行send 倒是很常见.大的网络应用里面 带宽是很恐怖的.
并且大的网络应用里面 server端得处理能力也是很恐怖的...
呵呵 我说100个线程 是有点过火了. 但我是举了个例子,不太恰当.
-----------------------------------------------
我是否可以认为,你还是承认了,线程不是越多越好?
而且,如果是做同一性质的工作,线程数目的确不应该超过CPU核心数+1,拿这个例子来说,不论瓶颈在CPU还是在网络接口,更多线程都是无意义的,如果是没有瓶颈的理想状态,那么CPU也已经达到或接近满负荷了。再说一点,线程调度的代价远比你想象的要大,因为这涉及到核心态和用户态的切换。
1.用户界面需要.
2.性能瓶颈不在cup的时候,就可以用多线程. 特别涉及到网络发送接收.我曾经用20~40个线程下载网站数据,整个程序就像一个下载器一样.只用一个线程来处理下载下来的数据.cpu也才最多70%.我用的还是 p4 单核的.但是网络就撑的满满的. 没办法客户说一定要快.现在做到不怕你电脑有多慢就怕你网络不够快.
有人说我用那多多线程浪费cpu资源.我说那也没办法.为了实现客户的要求的快.我必须牺牲以一点cpu资源来挤爆客户的网络.呵呵. 看应用来决定是否选择多线程.
有人说我用那多多线程浪费cpu资源.我说那也没办法.为了实现客户的要求的快.我必须牺牲以一点cpu资源来挤爆客户的网络.呵呵.
---------------------------------这样的做法是对使用同一服务器的其他客户的不公平,服务器总是尽可能公平地对待每个连接,你一个客户消耗20~40个连接,其他客户不用活了。
我对局域网中使用X雷的行为是深痛恶绝(当然,X雷的可恶之处不仅仅是使用多线程)。
那么你建立一个Http server 单线程...一个用户的请求处理完成之前下个请求完全等待.... 如果这个用户需要查询一个 1000万数据的表,耗时10秒.那么....如你所说,如果我这个还是分布式,还部署在多核心的PC SERVER上.莫非就真如你所所应该按 '单线程' 来写了?
现在的社会,我看不到有多少人会考虑其他人会怎么样,所以X雷和PPS之类的盛行。
远了远了,不扯了...
1,界面交互响应:以避免假死、无响应状态
2,socket通信的接受和发送端,这是为了提高效率个人认为多线程的目的主要在于并发,就是并行运行一些程序,而不是简单的提高程序效率,相反,有时候多线程的程序反而比单线程的效率低。再就是线程个数问题,我觉得这是应该是随场景环境而定的,超过不超过CPU数+1不重要。
多线程实际上是一个假象,就是说,因为CPU的时间总是有限的,那么CPU需要频繁地切换,在某个时间执行某个线程的任务。这种情况,如果用的不好,反而增加了CPU的负担,降低了系统性能
VS2010中提供了多CPU操作
Task Parallel Library(TPL)和Coordination Data Structures
dotnet多线程,初学者一般推荐使用:backgroudwork,效率相当不错,特别是继承它之后,使用reportprogress来与线程内部属性交互,可以直接操作UI,确实又傻瓜又简单,然后自己用list做个简单的线程池,外加线程的暂停,线程退出等功能,完全可以用在多线程下载之类的软件上
多线程并不是用来提高CPU的运算速度。你可以回顾操作系统的发展历史,从单作业系统到多作业系统,是为了充分利用CPU,防止在某线程正在等待其他资源(除CPU)是造成的CPU浪费。只是提高了CPU使用效率,同时满足用户响应需求。
在单CPU情况下,楼主所说的分为多个线程的做法,不仅不会降低运算时间,同时CPU还得消耗时间去进行线程之间的切换。是得不偿失的。 ---------
多线程并不是用来提高CPU的运算速度。你可以回顾操作系统的发展历史,从单作业系统到多作业系统,是为了充分利用CPU,是防止在某线程正在等待其他资源(除CPU)是造成的CPU浪费。提高了CPU使用效率,同时满足用户响应需求。这是另一原因。
在单CPU情况下,楼主所说的分为多个线程的做法,不仅不会降低运算时间,同时CPU还得消耗时间去进行线程之间的切换。是得不偿失的。 ---------
并行计算一般开CPU数或CPU*2的进程.以让CPU所有核心都利用到.
int[] 100万的数据,在单核机器上开多线程速度会比单线程慢,但是在10个核上,这10个线程是同时运行的,运行时间只有10万秒(实际上因为用同一个内存的原因,时间会远大于10万秒)
比如一个socket服务端程序,支持多个并发client的访问,如果能够预期到业务量不大的话,那么使用select完全可以满足要求,否则就需要分离多个线程单独处理了。
但是线程确实也不是越多越好,线程增加本身也会对操作系统的调度产生影响,我的理解线程池的作用就是避免频繁的创建新的线程去处理新的业务,而是尽量用已有的空闲线程来处理。以你的例子来说,1000万个数据,到底要用多少个线程才能使得干耗接近0,我们不知道,但是可以在程序中判断当还存在空闲的时候可以再调用线程池中的一个线程来处理。