php里面的->,相当于java里面的点吗?

// 更多阻塞的网络I/O

关于它如何与系统集成,就像这样:

相当简单:一个请求,一个进程。I/O是阻塞的。优点是什么呢?简单,可行。那缺点是什么呢?同时与20,000个客户端连接,你的服务器就挂了。由于内核提供的用于处理大容量I/O(epoll等)的工具没有被使用,所以这种方法不能很好地扩展。更糟糕的是,为每个请求运行一个单独的过程往往会使用大量的系统资源,尤其是内存,这通常是在这样的场景中遇到的第一件事情。

注意:Ruby使用的方法与PHP非常相似,在广泛而普遍的方式下,我们可以将其视为是相同的。

多线程的方式:Java

所以就在你买了你的第一个域名的时候,Java来了,并且在一个句子之后随便说一句“dot com”是很酷的。而Java具有语言内置的多线程(特别是在创建时),这一点非常棒。

大多数Java网站服务器通过为每个进来的请求启动一个新的执行线程,然后在该线程中最终调用作为应用程序开发人员的你所编写的函数。

在Java的Servlet中执行I/O操作,往往看起来像是这样:

// 更多阻塞的网络I/O

由于我们上面的doGet方法对应于一个请求并且在自己的线程中运行,而不是每次请求都对应需要有自己专属内存的单独进程,所以我们会有一个单独的线程。这样会有一些不错的优点,例如可以在线程之间共享状态、共享缓存的数据等,因为它们可以相互访问各自的内存,但是它如何与调度进行交互的影响,仍然与前面PHP例子中所做的内容几乎一模一样。每个请求都会产生一个新的线程,而在这个线程中的各种I/O操作会一直阻塞,直到这个请求被完全处理为止。为了最小化创建和销毁它们的成本,线程会被汇集在一起,但是依然,有成千上万个连接就意味着成千上万个线程,这对于调度器是不利的。

一个重要的里程碑是,在Java 1.4 版本(和再次显著升级的1.7 版本)中,获得了执行非阻塞I/O调用的能力。大多数应用程序,网站和其他程序,并没有使用它,但至少它是可获得的。一些Java网站服务器尝试以各种方式利用这一点; 然而,绝大多数已经部署的Java应用程序仍然如上所述那样工作。

Java让我们更进了一步,当然对于I/O也有一些很好的“开箱即用”的功能,但它仍然没有真正解决问题:当你有一个严重I/O绑定的应用程序正在被数千个阻塞线程狂拽着快要坠落至地面时怎么办。

作为一等公民的非阻塞I/O:Node

当谈到更好的I/O时,Node.js无疑是新宠。任何曾经对Node有过最简单了解的人都被告知它是“非阻塞”的,并且它能有效地处理I/O。在一般意义上,这是正确的。但魔鬼藏在细节中,当谈及性能时这个巫术的实现方式至关重要。

本质上,Node实现的范式不是基本上说“在这里编写代码来处理请求”,而是转变成“在这里写代码开始处理请求”。每次你都需要做一些涉及I/O的事情,发出请求或者提供一个当完成时Node会调用的回调函数。

在求中进行I/O操作的典型Node代码,如下所示:

可以看到,这里有两个回调函数。第一个会在请求开始时被调用,而第二个会在文件数据可用时被调用。

这样做的基本上给了Node一个在这些回调函数之间有效地处理I/O的机会。一个更加相关的场景是在Node中进行数据库调用,但我不想再列出这个烦人的例子,因为它是完全一样的原则:启动数据库调用,并提供一个回调函数给Node,它使用非阻塞调用单独执行I/O操作,然后在你所要求的数据可用时调用回调函数。这种I/O调用队列,让Node来处理,然后获取回调函数的机制称为“事件循环”。它工作得非常好。

然而,这个模型中有一道关卡。在幕后,究其原因,更多是如何实现Java V8 引擎(Chrome的JS引擎,用于Node)1,而不是其他任何事情。你所编写的JS代码全部都运行在一个线程中。思考一下。这意味着当使用有效的非阻塞技术执行I/O时,正在进行CPU绑定操作的JS可以在运行在单线程中,每个代码块阻塞下一个。 一个常见的例子是循环数据库记录,在输出到客户端前以某种方式处理它们。以下是一个例子,演示了它如何工作:

// 对每一行纪录进行处理

虽然Node确实可以有效地处理I/O,但上面的例子中的for循环使用的是在你主线程中的CPU周期。这意味着,如果你有10,000个连接,该循环有可能会让你整个应用程序慢如蜗牛,具体取决于每次循环需要多长时间。每个请求必须分享在主线程中的一段时间,一次一个。

这个整体概念的前提是I/O操作是最慢的部分,因此最重要是有效地处理这些操作,即使意味着串行进行其他处理。这在某些情况下是正确的,但不是全都正确。

另一点是,虽然这只是一个意见,但是写一堆嵌套的回调可能会令人相当讨厌,有些人认为它使得代码明显无章可循。在Node代码的深处,看到嵌套四层、嵌套五层、甚至更多层级的嵌套并不罕见。

我们再次回到了权衡。如果你主要的性能问题在于I/O,那么Node模型能很好地工作。然而,它的阿喀琉斯之踵(译者注:来自希腊神话,表示致命的弱点)是如果不小心的话,你可能会在某个函数里处理HTTP请求并放置CPU密集型代码,最后使得每个连接慢得如蜗牛。

在进入Go这一章节之前,我应该披露我是一名Go粉丝。我已经在许多项目中使用Go,是其生产力优势的公开支持者,并且在使用时我在工作中看到了他们。

也就是说,我们来看看它是如何处理I/O的。Go语言的一个关键特性是它包含自己的调度器。并不是每个线程的执行对应于一个单一的OS线程,Go采用的是“goroutines”这一概念。Go运行时可以将一个goroutine分配给一个OS线程并使其执行,或者把它挂起而不与OS线程关联,这取决于goroutine做的是什么。来自Go的HTTP服务器的每个请求都在单独的Goroutine中处理。

此调度器工作的示意图,如下所示:

这是通过在Go运行时的各个点来实现的,通过将请求写入/读取/连接/等实现I/O调用,让当前的goroutine进入睡眠状态,当可采取进一步行动时用信息把goroutine重新唤醒。

实际上,除了回调机制内置到I/O调用的实现中并自动与调度器交互外,Go运行时做的事情与Node做的事情并没有太多不同。它也不受必须把所有的处理程序代码都运行在同一个线程中这一限制,Go将会根据其调度器的逻辑自动将Goroutine映射到其认为合适的OS线程上。最后代码类似这样:

// 这里底层的网络调用是非阻塞的

正如你在上面见到的,我们的基本代码结构像是更简单的方式,并且在背后实现了非阻塞I/O。

在大多数情况下,这最终是“两个世界中最好的”。非阻塞I/O用于全部重要的事情,但是你的代码看起来像是阻塞,因此往往更容易理解和维护。Go调度器和OS调度器之间的交互处理了剩下的部分。这不是完整的魔法,如果你建立的是一个大型的系统,那么花更多的时间去理解它工作原理的更多细节是值得的; 但与此同时,“开箱即用”的环境可以很好地工作和很好地进行扩展。

Go可能有它的缺点,但一般来说,它处理I/O的方式不在其中。

谎言,诅咒的谎言和基准

对这些各种模式的上下文切换进行准确的定时是很困难的。也可以说这对你来没有太大作用。所以取而代之,我会给出一些比较这些服务器环境的HTTP服务器性能的基准。请记住,整个端对端的HTTP请求/响应路径的性能与很多因素有关,而这里我放在一起所提供的数据只是一些样本,以便可以进行基本的比较。

对于这些环境中的每一个,我编写了适当的代码以随机字节读取一个64k大小的文件,运行一个SHA-256哈希N次(N在URL的查询字符串中指定,例如.../test.php?n=100),并以十六进制形式打印生成的散列。我选择了这个示例,是因为使用一些一致的I/O和一个受控的方式增加CPU使用率来运行相同的基准测试是一个非常简单的方式。

首先,来看一些低并发的例子。运行2000次迭代,并发300个请求,并且每次请求只做一次散列(N = 1),可以得到:

时间是在全部并发请求中完成请求的平均毫秒数。越低越好。

很难从一个图表就得出结论,但对于我来说,似乎与连接和计算量这些方面有关,我们看到时间更多地与语言本身的一般执行有关,因此更多在于I/O。请注意,被认为是“脚本语言”(输入随意,动态解释)的语言执行速度最慢。

但是如果将N增加到1000,仍然并发300个请求,会发生什么呢 —— 相同的负载,但是hash迭代是之前的100倍(显着增加了CPU负载):

时间是在全部并发请求中完成请求的平均毫秒数。越低越好。

忽然之间,Node的性能显着下降了,因为每个请求中的CPU密集型操作都相互阻塞了。有趣的是,在这个测试中,PHP的性能要好得多(相对于其他的语言),并且打败了Java。(值得注意的是,在PHP中,SHA-256实现是用C编写的,执行路径在这个循环中花费更多的时间,因为这次我们进行了1000次哈希迭代)。

现在让我们尝试5000个并发连接(并且N = 1)—— 或者接近于此。不幸的是,对于这些环境的大多数,失败率并不明显。对于这个图表,我们会关注每秒的请求总数。越高越好:

每秒的请求总数。越高越好。

这张照片看起来截然不同。这是一个猜测,但是看起来像是对于高连接量,每次连接的开销与产生新进程有关,而与PHP + Apache相关联的额外内存似乎成为主要的因素并制约了PHP的性能。显然,Go是这里的冠军,其次是Java和Node,最后是PHP。

综上所述,很显然,随着语言的演进,处理大量I/O的大型应用程序的解决方案也随之不断演进。

为了公平起见,暂且抛开本文的描述,PHP和Java确实有可用于Web应用程序的非阻塞I/O的实现。 但是这些方法并不像上述方法那么常见,并且需要考虑使用这种方法来维护服务器的伴随的操作开销。更不用说你的代码必须以与这些环境相适应的方式进行结构化; “正常”的PHP或Java Web应用程序通常不会在这样的环境中进行重大改动。

作为比较,如果只考虑影响性能和易用性的几个重要因素,可以得到:

语言线程或进程非阻塞I/O易用性

线程通常要比进程有更高的内存效率,因为它们共享相同的内存空间,而进程则没有。结合与非阻塞I/O相关的因素,当我们向下移动列表到一般的启动时,因为它与改善I/O有关,可以看到至少与上面考虑的因素一样。如果我不得不在上面的比赛中选出一个冠军,那肯定会是Go。

即便这样,在实践中,选择构建应用程序的环境与你的团队对于所述环境的熟悉程度以及可以实现的总体生产力密切相关。因此,每个团队只是一味地扎进去并开始用Node或Go开发Web应用程序和服务可能没有意义。事实上,寻找开发人员或内部团队的熟悉度通常被认为是不使用不同的语言和/或不同的环境的主要原因。也就是说,过去的十五年来,时代已经发生了巨大的变化。

希望以上内容可以帮助你更清楚地了解幕后所发生的事件,并就如何处理应用程序现实世界中的可扩展性为你提供的一些想法。快乐输入,快乐输出!

看完本文有收获?请转发分享给更多人

关注「数据库开发」,提升 DB 技能

首先从概念上区分,Java是一门面向对象编程语言,具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特性;PHP是一种通用开源脚本语言,语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛。

其次从学习难易程度上区分,PHP比Java简单很多。Java对学历有要求,本科及以上学历的人群比较适合学Java、也能学会Java。而PHP的学历要求比较低,大专、初高中学历的人群也是可以学会PHP的。

第三从应用领域上区分,PHP主要是应用在网站方面,它适合快速开发,中小型应用系统,开发成本低,有什么变动也能及时调整。而Java的应用领域要广泛的多,因为Java有完善的框架,在多线程、高并发方面有着较好的稳定性,所以在网站、嵌入式领域、金融行业服务器、安卓应用等领域都需要Java开发的人才。

最后从发展前景上区分,如果你以后想专注于WEB领域的发展,那么学PHP就够用了,而Java适用于大型系统,如果你不打算只做web就需要学Java了。职友集上统计的北京PHP开发的平均薪资为19260元每月,Java开发20440元每月,不论PHP还是Java前景都很不错。

以上就是小编从四方面对比的PHP和Java的区别。如果你还想更详细的了解PHP和Java可以(加群暗号:领资料)。群里有免费的学习资料,还有专业老师为你解惑,更有免费体验课、免费直播课等福利不定期放送。

PHP 里的单例模式一般的写法

但是网上查到的资料都是 强调 java 里面使用单例模式的时候需要使用线程安全的写法

所以想请问下 PHP 的这种单例写法,是因为 PHP 内部有其他处理已经做到线程安全,还是说这样并不安全,有其他更完善的写法补充。。。求教 =。=,感谢

  1. 当客户端发送一个请求时,web server 会通过一个 php-fpm 进程(这里和下文所说指的 fpm 进程都是 fpm 开启的 worker 进程,关于 fpm 的工作原理这里不再累述)去执行 php 代码,php 代码的执行是单线程的。
  2. 那么,当有多个客户端同时发送请求时(并发),web server 就会为每个请求开启一个 php-fpm 进程去执行 php 代码。
  3. 请求执行过后,对应的 php-fpm 进程被销毁,内存得以释放。
  4. 而并发的问题在于,在某一时间,客户端请求让 php-fpm 进程数量达到了最大限制数,这个时候,新来的请求只能等待空闲的 php-fpm 来处理,这就是多进程同步阻塞模式的弊端,当然还有进程过多所带来的内存占用问题。

我要回帖

更多关于 gt740相当于什么显卡 的文章

 

随机推荐