84669 Lernen von Personen
152542 Lernen von Personen
20005 Lernen von Personen
5487 Lernen von Personen
7821 Lernen von Personen
359900 Lernen von Personen
3350 Lernen von Personen
180660 Lernen von Personen
48569 Lernen von Personen
18603 Lernen von Personen
40936 Lernen von Personen
1549 Lernen von Personen
1183 Lernen von Personen
32909 Lernen von Personen
请问为什么到底什么样的业务是计算密集型,什么样的业务是IO密集型?为什么说PHP最初设计是针对计算机密集型的,node.js是针对IO密集型的?
昨天看廖雪峰博客中刚好有一章节讲到:计算密集型 vs. IO密集型,摘录如下:
我们可以把任务分为计算密集型和IO密集型。 计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。 计算密集型任务由于主要消耗CPU资源,因此,代码运行效率至关重要。Python这样的脚本语言运行效率很低,完全不适合计算密集型任务。对于计算密集型任务,最好用C语言编写。 IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。 IO密集型任务执行期间,99%的时间都花在IO上,花在CPU上的时间很少,因此,用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言,完全无法提升运行效率。对于IO密集型任务,最合适的语言就是开发效率最高(代码量最少)的语言,脚本语言是首选,C语言最差。
我们可以把任务分为计算密集型和IO密集型。
计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。
计算密集型任务由于主要消耗CPU资源,因此,代码运行效率至关重要。Python这样的脚本语言运行效率很低,完全不适合计算密集型任务。对于计算密集型任务,最好用C语言编写。
IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。
IO密集型任务执行期间,99%的时间都花在IO上,花在CPU上的时间很少,因此,用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言,完全无法提升运行效率。对于IO密集型任务,最合适的语言就是开发效率最高(代码量最少)的语言,脚本语言是首选,C语言最差。
有一个被用烂了的栗子,解释 Node.js 语言 非阻塞,事件驱动 概念,大约是这样的:
非阻塞
事件驱动
你到餐馆吃饭,餐馆里的服务员在帮你点单之后,会直接把菜单塞给厨房,然后立刻去到下一位顾客处,而非在厨房等待(阻塞)。直到烹饪结束后,厨师大喊“来拿菜”(事件)。服务员跑回厨房,把菜品端到你的桌子上(事件处理/回调)
阻塞
事件
事件处理
回调
在这个栗子中,我们可以简单的理解为:服务员相当于 CPU,而厨房的工作就是I/O。显然的,在一个饭店里,服务员的工作并不复杂,”等待上菜的时间“多数是花在”等待厨房“上。这与如今大多数网站的情况相似:网站通常不需要做太多复杂的运算,但需要花费大量的时间等待 I/O 处理,比如数据库查询,比如图片、视频的读取。
CPU
I/O
于是 Node.js 舍弃了传统 Web 服务中“每当一次请求来临,都打开一个线程来单独处理”的做法,而是采用事件驱动的模型,默认情况下,仅用单线程就可以负担相当高的并发量。
于是在这种情境下,我们说:Node.js 更适合 IO密集型的任务处理。
Node.js 更适合 IO密集型的任务处理
但如果我们把上面的栗子更换一下,比如说咱们不开饭馆,开银行。每当客户到来,要求取出指定的款项,作为服务员,你需要根据客户的账户等级计算利率,计算利息,计算分红,等等……(随意想到的比方,可能不太恰当),而“取钱并交给客户”这个动作本身却并不复杂。
这时候,就不能指望像饭店那样,只靠一个服务员就能应付大量的客户,因为每个请求都需要独占服务员大量的时间(不可避免的阻塞)。那么此时,传统的模型,例如 PHP 或许就变得更加合适了。
以上,希望能解你所惑
IO密集型:就是IO比较多的应用,比如网络传输、数据库等调用。web应用大多数是这种
计算密集型:顾名思义就是需要大量的CPU计算的应用类型。像云计算一类的应用应该属于这种。
什么是计算密集?举个例子,把SQLite数据库放到Linux内存文件系统/dev/shm上对100万数据进行SELECT查询操作,那么这个SELECT查询,在使用了B+树索引时,在B+树索引上的二分查找就是典型的密集计算,如果没有使用索引,那单纯的扫描整个表也是密集计算.所以说,像关系数据库这种东西,普遍都是使用C/C++实现,保证性能和控制内存占用.
什么是IO密集?比如SQLite数据库不在内存,而在普通机械磁盘上,这时写操作(INSERT/UPDATE/DELETE)都是典型的IO密集操作,因为这时就算CPU再快,SQLite引擎再快,也会被机械磁盘的写入操作拖慢.所以为了并发,SQLite后来引入了WAL(write-ahead log)预写式日志支持,具体配置就是执行一下SQLite查询:
WAL(write-ahead log)
PRAGMA synchronous = NORMAL; PRAGMA journal_mode = WAL;
WAL机制的原理是: 修改并不直接写入到数据库文件中,而是写入到另外一个称为WAL的文件中(data.db3-wal). 如果事务失败,WAL中的记录会被忽略,撤销修改. 如果事务成功,它将在随后的某个时间(PRAGMA synchronous = NORMAL)被写回到数据库文件中,提交修改. 同步WAL文件和数据库文件的行为被称为checkpoint(检查点),它由SQLite自动执行, 默认是在WAL文件积累到1000页修改的时候(PRAGMA wal_autocheckpoint). 在适当的时候,也可以手动执行checkpoint,SQLite提供了相关的接口,执行 PRAGMA wal_checkpoint 之后,WAL文件会被清空. 在读的时候,SQLite将在WAL文件中搜索,找到最后一个写入点,记住它,并忽略在此之后的写入点(这保证了读写和读读可以并行执行). 随后,它确定所要读的数据所在页是否在WAL文件中,如果在,则读WAL文件中的数据,如果不在,则直接读数据库文件中的数据. 在写的时候,SQLite将之写入到WAL文件中即可,但是必须保证独占写入,因此写与写之间不能并行执行. WAL在实现的过程中,使用了共享内存技术(data.db3-shm),因此,所有的读写进程必须在同一个机器上,否则,无法保证数据一致性.
像WAL和checkpoint这种概念,在其他数据库比如MySQL中也存在,只不过MySQL会更复杂,能支持更大规模的并发写操作.像WAL+checkpoint这种写入方式,你就可以看做是一种异步的写入.
WAL+checkpoint
Node的JS解释器基于Chromium的V8,而V8具有JIT即时编译机制,所以Node的密集计算的性能是要比PHP强的.虽然PHP官方现在也在开发PHP的JIT试验分之,但其性能仍然不如V8.不过就算Node计算性能好,也几乎不会有人推荐在Node里执行大规模的密集计算,因为密集计算耗必定阻塞Node服务,这和Node倡导的无阻塞理念相背.
Node利用JS事件驱动的特性,做到了无阻塞,但基于回调的事件编程方式不利于代码维护.而且Node这种服务不能像Tomcat这类Java服务使用单进程多线程利用多核,而V8也并不是为多线程设计,所以Node官方只能自己搞了一个cluster多进程模块来利用多核.
PHP比较中庸,计算速度比不上JIT语言,但在非JIT的通用脚步语言中,PHP并不慢,比方说PHP5就已经比Python快,PHP7更是比Python快得多,比如php-src/Zend/bench.php测试中,PHP 7.1的耗时只有5.4的1/4.
另外PHP的PHP-FPM和Apache MOD_PHP这类多进程的FastCGI运行方式,也很容易利用多核.而且还能开启opcache缓存PHP脚本的opcode到共享内存.也就是说,假设你定义了很多函数在functions.php里,opcache缓存该脚本在内存后,其后每次请求PHP都不必重新解析脚本,直接就能执行opcode,性能提升是非常明显的,尤其对于复杂的PHP应用.
昨天看廖雪峰博客中刚好有一章节讲到:计算密集型 vs. IO密集型,摘录如下:
有一个被用烂了的栗子,解释 Node.js 语言
非阻塞
,事件驱动
概念,大约是这样的:在这个栗子中,我们可以简单的理解为:服务员相当于
CPU
,而厨房的工作就是I/O
。显然的,在一个饭店里,服务员的工作并不复杂,”等待上菜的时间“多数是花在”等待厨房“上。这与如今大多数网站的情况相似:网站通常不需要做太多复杂的运算,但需要花费大量的时间等待 I/O 处理,比如数据库查询,比如图片、视频的读取。于是 Node.js 舍弃了传统 Web 服务中“每当一次请求来临,都打开一个线程来单独处理”的做法,而是采用事件驱动的模型,默认情况下,仅用单线程就可以负担相当高的并发量。
于是在这种情境下,我们说:
Node.js 更适合 IO密集型的任务处理
。但如果我们把上面的栗子更换一下,比如说咱们不开饭馆,开银行。每当客户到来,要求取出指定的款项,作为服务员,你需要根据客户的账户等级计算利率,计算利息,计算分红,等等……(随意想到的比方,可能不太恰当),而“取钱并交给客户”这个动作本身却并不复杂。
这时候,就不能指望像饭店那样,只靠一个服务员就能应付大量的客户,因为每个请求都需要独占服务员大量的时间(不可避免的
阻塞
)。那么此时,传统的模型,例如 PHP 或许就变得更加合适了。以上,希望能解你所惑
IO密集型:就是IO比较多的应用,比如网络传输、数据库等调用。web应用大多数是这种
计算密集型:顾名思义就是需要大量的CPU计算的应用类型。像云计算一类的应用应该属于这种。
什么是计算密集?举个例子,把SQLite数据库放到Linux内存文件系统/dev/shm上对100万数据进行SELECT查询操作,那么这个SELECT查询,在使用了B+树索引时,在B+树索引上的二分查找就是典型的密集计算,如果没有使用索引,那单纯的扫描整个表也是密集计算.所以说,像关系数据库这种东西,普遍都是使用C/C++实现,保证性能和控制内存占用.
什么是IO密集?比如SQLite数据库不在内存,而在普通机械磁盘上,这时写操作(INSERT/UPDATE/DELETE)都是典型的IO密集操作,因为这时就算CPU再快,SQLite引擎再快,也会被机械磁盘的写入操作拖慢.所以为了并发,SQLite后来引入了
WAL(write-ahead log)
预写式日志支持,具体配置就是执行一下SQLite查询:WAL机制的原理是: 修改并不直接写入到数据库文件中,而是写入到另外一个称为WAL的文件中(data.db3-wal). 如果事务失败,WAL中的记录会被忽略,撤销修改. 如果事务成功,它将在随后的某个时间(PRAGMA synchronous = NORMAL)被写回到数据库文件中,提交修改. 同步WAL文件和数据库文件的行为被称为checkpoint(检查点),它由SQLite自动执行, 默认是在WAL文件积累到1000页修改的时候(PRAGMA wal_autocheckpoint). 在适当的时候,也可以手动执行checkpoint,SQLite提供了相关的接口,执行 PRAGMA wal_checkpoint 之后,WAL文件会被清空. 在读的时候,SQLite将在WAL文件中搜索,找到最后一个写入点,记住它,并忽略在此之后的写入点(这保证了读写和读读可以并行执行). 随后,它确定所要读的数据所在页是否在WAL文件中,如果在,则读WAL文件中的数据,如果不在,则直接读数据库文件中的数据. 在写的时候,SQLite将之写入到WAL文件中即可,但是必须保证独占写入,因此写与写之间不能并行执行. WAL在实现的过程中,使用了共享内存技术(data.db3-shm),因此,所有的读写进程必须在同一个机器上,否则,无法保证数据一致性.
像WAL和checkpoint这种概念,在其他数据库比如MySQL中也存在,只不过MySQL会更复杂,能支持更大规模的并发写操作.像
WAL+checkpoint
这种写入方式,你就可以看做是一种异步的写入.Node的JS解释器基于Chromium的V8,而V8具有JIT即时编译机制,所以Node的密集计算的性能是要比PHP强的.虽然PHP官方现在也在开发PHP的JIT试验分之,但其性能仍然不如V8.不过就算Node计算性能好,也几乎不会有人推荐在Node里执行大规模的密集计算,因为密集计算耗必定阻塞Node服务,这和Node倡导的无阻塞理念相背.
Node利用JS事件驱动的特性,做到了无阻塞,但基于回调的事件编程方式不利于代码维护.而且Node这种服务不能像Tomcat这类Java服务使用单进程多线程利用多核,而V8也并不是为多线程设计,所以Node官方只能自己搞了一个cluster多进程模块来利用多核.
PHP比较中庸,计算速度比不上JIT语言,但在非JIT的通用脚步语言中,PHP并不慢,比方说PHP5就已经比Python快,PHP7更是比Python快得多,比如php-src/Zend/bench.php测试中,PHP 7.1的耗时只有5.4的1/4.
另外PHP的PHP-FPM和Apache MOD_PHP这类多进程的FastCGI运行方式,也很容易利用多核.而且还能开启opcache缓存PHP脚本的opcode到共享内存.也就是说,假设你定义了很多函数在functions.php里,opcache缓存该脚本在内存后,其后每次请求PHP都不必重新解析脚本,直接就能执行opcode,性能提升是非常明显的,尤其对于复杂的PHP应用.