您的位置 首页 php

PHP中关于网络并发的问题,是最让程序员头疼的吗?

图片来源呼和浩特中公教育hhhtfxzgjy

关于并发性能问题(这里主要指网络并发),无论开源社区还是学术领域都已经做出过深入的研究,而且经过多年的验证,现在已经非常成熟,且在业内达成了广泛的共识。尽管已经有了比较优秀的解决方案,但为什么目前互联网上大部分的项目却依然采用传统并发模型架构呢?

想要知道这其中的原因,我们得看看开发领域多年来并发模型的流行趋势与变化及其原理,而且今天呼和浩特中公教育除了要帮助大家掌握各种不同的并发模型外,还会给大家提供一些有价值的思路,至少我们可以在我们的下一个项目中采用一种高性能的,现代化的并发模型架构来完成项目开发。

早期的 编程语言 ,比如c和c +
+,这些语言被发明的时候网络还不发达,硬件速度也比较慢,大部分应用都是基于某种计算机的本地应用,因此编程语言并没有在语言底层支持并发,如果有需要,程序员可以自己动手设计自己的并发模型。

现在的高级语言比如 java 、php、go、nodejs等语言环境广泛应用于web项目,既然是web项目,并发的处理就非常重要了,因此现代化的web开发语言环境通常都提供了标准的并发模型来简化开发者的工作。

先来看看php的并发模型,例如:呼和浩特U就业php在web开发领域也算是历史悠久了,LAMP已经成为互联网架构的经典组合,Linux的各个发行版几乎都集成了对LAMP的支持,LAMP中PHP的并发模型比较简单,采用的是多进程并发模型(windows下可以支持 多线程 ),所谓进程即操作系统中独立应用程序的载体,进程包含一个应用程序所需的一切资源,包括程序使用的内存以及CPU的使用权。

那么php的多进程模型是如何支持多用户同时访问web服务的呢?我们知道cpu的一个内核同一时刻只能执行一条指令,理论上来说单核cpu并不存在真正意义上的并行操作,如果是双核cpu,也只能是2个指令同时执行,同理,四核、八核越多的核能支持越多的指令同时执行。

我们能看到,即便只有一核的cpu也能运行多任务,这是怎么做到的?

要知道答案我们需要了解我们使用的操作系统,无论windows还是linux,都通过多进程支持多任务,多进程只所以可以达成是因为我们现在的cpu速度足够快,每秒钟能执行几十亿次的指令,而人的反应时间相对cpu则慢太多太多。多进程是由操作系统将cpu的运算时间切分成很小的时间段,然后将这些时间分配给系统中运行的进程,当这个切换速度足够快,快到人反应不过来的时候,我们就觉得他们是同时发生的。

而php在面对很多用户同时访问web服务的时候,会为每一个用户的请求创建一个进程,分配相应的内存与cpu时间,而cpu在处理这些请求的时候,实际上是飞快的在多个用户请求中切换,用户感觉到的则是服务器实时的响应了用户的请求。

多进程的并发模型有一个很大的优势,在针对特定业务开发程序时不需要有太多顾虑,大部分情况下不需要程序员思考并发问题,这样让web开发工作变得简单起来。

图片来源呼和浩特中公教育

Java与php不同,目前大部分java项目都采用多线程并发模型,但java语言本身并没有从底层去定义一个通用的并发模型,也就是说,使用java的用户可以像c程序员一样去实现自己的并发模型

Java多 线程 并发模型源于 javaEE 的规范,在javaEE的规范中,web开发者将符合javaEE规范的程序打包后通过javaEE容器部署,而容器本身就是一个java程序,当用户访问javaEE项目时,javaEE容器会为用户请求创建一个线程,多用户同时访问的时候就会产生许多新的线程。

多线程并发模型编程让 程序设计 变的复杂,但是创建线程的开销要大大的小于创建一个进程,当操作系统把cpu时间交给进程后,进程可以进一步把自己拥有的cpu时间切分给并行执行的多个线程,与进程切换不同,进程切换是由操作系统完成,但切换线程的工作则是在进程中完成。

毫无疑问,javaEE给java开发者带来了巨大的福音,因为线程的并发冲突处理,线程的创建与销毁等一些列繁琐的事情统统都有容器去处理,而普通开发者只需要关注业务本身去编写相应的逻辑代码就可以了。

大家可以看到,使php与java成为最流行web开发语言的原因不是别的,而是易用性,开发者不用关心并发而写出的程序却都是支持并发访问的,这使开发成为一件愉快的事情。

但随着互联网对人们日常生活的不断渗透,web应用也对开发者提出了更高的要求。现在我们所处的时代,许多新兴的平台和应用会在不经意间轻易的突破用户百万,以前只有那些行业巨头们才会承担的web负载能力问题将会出现在更多开发者面前。

可以说无论PHP的多进程并发模型还是javaEE的多线程并发模型,在并发性能上都存在着明显的不足

可以想象一下,由于采用多进程与多线程处理并发,cpu的处理时间是被切分成很小的时间段,如果用户业务程序得到cpu的使用权后并没有给cpu下达任何指令会发生什么事情呢?

答案是大量的cpu资源被浪费掉了。当用户发送一个请求到服务器端开始,我们就为处理用户请求创建了进程(或线程),那么在这个进程(或线程中)就会占用一部分的系统资源,然而我们遇到需要查询数据库、读写文件等操作时,我们会发送请求给数据库或者通过系统调用来获取文件资源,而这些操作通常会很慢,我们需要拿到结果以后才能执行下一行指令,等待的时间通常会比cpu分配给我们的时间片段长的多,也许我们要等待进程(线程)切换上百次甚至上千次后才能拿到结果,而这期间的cpu资源全部都被浪费掉。

上面这种只有上一步完成后才能进行下一步操作的程序设计方式被称作
“同步”,典型的php站点以及javaEE程序都是以同步的方式在运行,因此这样的架构中通常都存在着大量的性能浪费。

有没并发模型能避免这样的浪费呢?

当然有,而且还有很多。

在这里内蒙中公小U给大家介绍两种主流的并发模型

一种并发模型采用异步编程模型实现,另一种则采用比线程更轻的协程。

其实javaEE在异步编程方面也是做出过努力和尝试的,比如java中的NIO就是一个典型,只是由于NIO本身设计过于复杂,这使得这一机制并没有得到广泛的应用。

异步编程成功的典型代表就是nodejs,javascript本身就对事件循环有很好的支持,采用观察者模式,使用事件循环,让所有的操作都异步执行,遇到需要等待的操作只需要绑定一个事件并传递 回调函数 ,当消息循环检测事件触发后再调用回调函数,这样所有代码都是异步执行,没有所谓等待过程,也不需要做任何的上下文切换,于是nodejs在性能上得到了巨大的提升,单进程单线程就能扛起并发百万,相对于传统的javaEE项目来说,简直就是一个怪胎。

协程在很多现代化的编程语言中都有很好的支持,尤其在多核多线程的硬件支持下,使得它比单进程单线程的nodejs使用起来更加方便,比如go语言就是这方面的强者。

协程与线程很类似,也是在一个进程中分出很多小的线程来,cpu的使用权也是在这些小的线程中切换,但与普通线程不同的是,协程可以在等待其他资源的时候主动的让出cpu使用权,从而避免资源的浪费。虽然经典的java程序不支持协程,但本质上协程和java社区中的绿色线程或轻线程是类似的。

既然我们已经知道传统web项目的性能到底消耗在哪里,那么我们可以做些什么呢?我们需要让我们项目采用全异步编程吗?我们需要让我们的项目支持协程吗?

或许没有我们想的那么容易,nodejs并发性能很好,但我们却发现商业项目中只有那些强交互型的应用会大规模采用nodejs,而业务复杂度高的项目却几乎都还是php的天下,对于协程支持很好的go语言目前大规模使用的也只有七牛云存储一家公司。

倘若一个项目采用全异步编程,那么项目开发的难度必然大增,具体原因就不在这里分析了,相信熟悉js的同学们自然会有所体会。协程虽不至于让程序流程混乱,但如果没有高级的中间件支持,是需要开发者自行创建协程并且自行判断什么时候该让出cpu使用权的,项目中会多出很多类似yield
return的代码,开发难度与项目管理的复杂度自然大幅提升。

如果希望我们的项目中能获得性能的改进而不让复杂度大幅增加,我们可以很简单的就做到一些事情。

如果你是java程序员,那么请你认清一个事实,web开发不等于javaEE,如果摆脱javaEE的体系,我们可以有更多更好的选择,如果依然采用javaEE,至少我们应该升级到java8,java8带来的函数式编程能让我们更好的支持异步编程。

如果是php程序员,我们使用nginx替代apache时就已经从同步IO切换到异步IO了,但要注意一点,php本身还是同步的,想要进一步提升性能,我们可以把php的耗时操作全部抛出去,无论通过消息队列还是计划任务,不管怎样,分布式是必然。

文章来源:智云一二三科技

文章标题:PHP中关于网络并发的问题,是最让程序员头疼的吗?

文章地址:https://www.zhihuclub.com/150744.shtml

关于作者: 智云科技

热门文章

网站地图