<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PHP on 庞玉栋个人博客</title><link>https://pangyd.com/tags/php/</link><description>Recent content in PHP on 庞玉栋个人博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 22 Nov 2018 19:06:17 +0800</lastBuildDate><atom:link href="https://pangyd.com/tags/php/index.xml" rel="self" type="application/rss+xml"/><item><title>人生苦短,我用python “Life is short. You need Python.”</title><link>https://pangyd.com/post/207-python-life-is-short-you-need-python/</link><pubDate>Fri, 09 Nov 2018 08:22:51 +0800</pubDate><guid>https://pangyd.com/post/207-python-life-is-short-you-need-python/</guid><description>&lt;p>&lt;img src="https://pangyd.com/uploads/2018/09/f0c1d12340235ebb.jpg" alt="index.jpg">&lt;/p>&lt;p>&lt;span>&lt;span>Python 在约 40 年前出现，现在已经有数以千计基于这项技术的网站和软件项目。Python 因其独有的特点从众多开发语言中脱颖而出，深受世界各地的开发者喜爱。&lt;/span>&lt;/span>&lt;/p>&lt;p style="text-align: center">&lt;span>正文共：4565 字&amp;nbsp;&lt;/span>&lt;/p>&lt;p style="text-align: center">&lt;span>预计阅读时间：12 分钟&lt;/span>&lt;/p>&lt;p>人生苦短， 我用 Python ，不知道从什么时候开始，这句话开始流行。&lt;/p>&lt;p>&lt;img title="" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='120'%3E%3Crect width='480' height='120' fill='%230E1012' stroke='%231B1E22'/%3E%3Ctext x='240' y='66' fill='%235C6069' font-family='monospace' font-size='13' text-anchor='middle'%3E%5B%E5%8E%9F%E5%9B%BE%E5%B7%B2%E5%A4%B1%E6%95%88%5D%3C/text%3E%3C/svg%3E" alt="640?wx_fmt=jpeg&amp;wxfrom=5&amp;wx_lazy=1" border="0">&lt;/p>&lt;p>人们可能会说， 2017 年是 Python 辉煌的一年。毕竟在这一年中，Python 的增长速度令人惊艳。&lt;/p>&lt;p>&lt;img title="" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='120'%3E%3Crect width='480' height='120' fill='%230E1012' stroke='%231B1E22'/%3E%3Ctext x='240' y='66' fill='%235C6069' font-family='monospace' font-size='13' text-anchor='middle'%3E%5B%E5%8E%9F%E5%9B%BE%E5%B7%B2%E5%A4%B1%E6%95%88%5D%3C/text%3E%3C/svg%3E" alt="640?wx_fmt=jpeg&amp;wxfrom=5&amp;wx_lazy=1" border="0">&lt;/p>&lt;p style="text-align: center">&lt;span>主要编程语言的增长趋势，图片来自 Stack Overflow&lt;/span>&lt;/p>&lt;p>在GitHub 2017年度报告中，Python 超越 Java 成第二受欢迎语言。在 ranked.com 的排名中，Python 是 2017 年最受欢迎人工智能编程语言（第二是 C++，R 并未上榜）。&lt;/p>&lt;p>根据 Stack Overflow 流量统计，2017 年 6 月，Python 第一次成为高收入国家 Stack Overflow 访问量最大的标签。&lt;/p>&lt;p>&lt;img class="img_loading" title="" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='120'%3E%3Crect width='480' height='120' fill='%230E1012' stroke='%231B1E22'/%3E%3Ctext x='240' y='66' fill='%235C6069' font-family='monospace' font-size='13' text-anchor='middle'%3E%5B%E5%8E%9F%E5%9B%BE%E5%B7%B2%E5%A4%B1%E6%95%88%5D%3C/text%3E%3C/svg%3E" alt="640?wx_fmt=jpeg" border="0">&lt;/p>&lt;p>在 TIOBE 2018 年 4 月编程语言排行榜前 20 名中，Python 已跃居到第四位，前三分别为为 Java ，C、C++。&lt;/p></description></item><item><title>服务端 I/O 性能大比拼：Node、PHP、Java 和 Go</title><link>https://pangyd.com/post/134-i-o-nodephpjava-go/</link><pubDate>Sat, 14 Oct 2017 19:47:46 +0800</pubDate><guid>https://pangyd.com/post/134-i-o-nodephpjava-go/</guid><description>&lt;p>理解应用程序的输入/输出（I/O）模型，意味着其在计划处理负载与残酷的实际使用场景之间的差异。若应用程序比较小，也没有服务于很高的负载，也许它影响甚微。但随着应用程序的负载逐渐上涨，采用错误的I/O模型有可能会让你到处踩坑，伤痕累累。&lt;/p>&lt;p>正如大部分存在多种解决途径的场景一样，重点不在于哪一种途径更好，而是在于理解如何进行权衡。让我们来参观下I/O的景观，看下可以从中窃取点什么。&lt;/p>&lt;p>&lt;img data-src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" class="" data-ratio="1" data-w="1280" data-type="jpeg" src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" data-fail="0">&lt;/p>&lt;p>在这篇文章，我们将会结合Apache分别比较Node，Java，Go，和PHP，讨论这些不同的语言如何对他们的I/O进行建模，各个模型的优点和缺点，并得出一些初步基准的结论。如果关心你下一个Web应用的I/O性能，那你就找对文章了。&lt;/p>&lt;h2>I/O基础知识：快速回顾&lt;/h2>&lt;p>为了理解与I/O密切相关的因素，必须先来回顾在操作系统底层的概念。虽然不会直接处理这些概念的大部分，但通过应用程序的运行时环境你一直在间接地处理他们。而关键在于细节。&lt;/p>&lt;h3>系统调用&lt;/h3>&lt;p>首先，我们有系统调用，它可以描述成这样：&lt;/p>&lt;ul class="list-paddingleft-2">&lt;li>&lt;p>你的程序（在“用户区域”，正如他们所说的）必须让操作系统内核在它自身执行I/O操作。&lt;/p>&lt;/li>&lt;li>&lt;p>“系统调用”（syscall）意味着你的程序要求内核做某事。不同的操作系统，实现系统调用的细节有所不同，但基本的概念是一样的。这将会有一些特定的指令，把控制权从你的程序转交到内核（类似函数调用但有一些专门用于处理这种场景的特殊sauce）。通常来说，系统调用是阻塞的，意味着你的程序需要等待内核返回到你的代码。&lt;/p>&lt;/li>&lt;li>&lt;p>内核在我们所说的物理设备（硬盘、网卡等）上执行底层的I/O操作，并回复给系统调用。在现实世界中，内核可能需要做很多事情才能完成你的请求，包括等待设备准备就绪，更新它的内部状态等，但作为一名应用程序开发人员，你可以不用关心这些。以下是内核的工作情况。&lt;/p>&lt;/li>&lt;/ul>&lt;p>&lt;img data-src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" class="" data-ratio="1" data-w="1280" data-type="jpeg" src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" data-fail="0">&lt;/p>&lt;h3>阻塞调用与非阻塞调用&lt;/h3>&lt;p>好了，我刚刚在上面说系统调用是阻塞的，通常来说这是对的。然而，有些调用被分类为“非阻塞”，意味着内核接收了你的请求后，把它放进了队列或者缓冲的某个地方，然后立即返回而并没有等待实际的I/O调用。所以它只是“阻塞”了一段非常短的时间，短到只是把你的请求入列而已。&lt;/p>&lt;p>这里有一些有助于解释清楚的（Linux系统调用）例子：&lt;code>-read()&lt;/code>是阻塞调用——你传给它一个文件句柄和一个存放所读到数据的缓冲，然后此调用会在当数据好后返回。注意这种方式有着优雅和简单的优点。&lt;code>-epoll_create()&lt;/code>，&lt;code>epoll_ctl()&lt;/code>，和&lt;code>epoll_wait()&lt;/code>这些调用分别是，让你创建一组用于侦听的句柄，从该组添加/删除句柄，和然后直到有活动时才阻塞。这使得你可以通过一个线程有效地控制一系列I/O操作。如果需要这些功能，这非常棒，但也正如你所看到的，使用起来当然也相当复杂。&lt;/p>&lt;p>理解这里分时差异的数量级是很重要的。如果一个CPU内核运行在3GHz，在没有优化的情况下，它每秒执行30亿次循环（或者每纳秒3次循环）。非阻塞系统调用可能需要10纳秒这样数量级的周期才能完成——或者“相对较少的纳秒”。对于正在通过网络接收信息的阻塞调用可能需要更多的时间——例如200毫秒（0.2秒）。例如，假设非阻塞调用消耗了20纳秒，那么阻塞调用消耗了200,000,000纳秒。对于阻塞调用，你的程序多等待了1000万倍的时间。&lt;/p>&lt;p>&lt;img data-src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" class="" data-ratio="1" data-w="1280" data-type="jpeg" src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" data-fail="0">&lt;/p>&lt;p>内核提供了阻塞I/O（“从网络连接中读取并把数据给我”）和非阻塞I/O（“当这些网络连接有新数据时就告诉我”）这两种方法。而使用何种机制，对应调用过程的阻塞时间明显长度不同。&lt;/p>&lt;h3>调度&lt;/h3>&lt;p>接下来第三件关键的事情是，当有大量线程或进程开始阻塞时怎么办。&lt;/p>&lt;p>出于我们的目的，线程和进程之间没有太大的区别。实际上，最显而易见的执行相关的区别是，线程共享相同的内存，而每个进程则拥有他们独自的内存空间，使得分离的进程往往占据了大量的内存。但当我们讨论调度时，它最终可归结为一个事件清单（线程和进程类似），其中每个事件需要在有效的CPU内核上获得一片执行时间。如果你有300个线程正在运行并且运行在8核上，那么你得通过每个内核运行一段很短的时间然后切换到下一个线程的方式，把这些时间划分开来以便每个线程都能获得它的分时。这是通过“上下文切换”来实现的，使得CPU可以从正在运行的某个线程/进程切换到下一个。&lt;/p>&lt;p>这些上下文切换有一定的成本——它们消耗了一些时间。在快的时候，可能少于100纳秒，但是根据实现的细节，处理器速度/架构，CPU缓存等，消耗1000纳秒甚至更长的时间也并不罕见。&lt;/p>&lt;p>线程（或者进程）越多，上下文切换就越多。当我们谈论成千上万的线程，并且每一次切换需要数百纳秒时，速度将会变得非常慢。&lt;/p>&lt;p>然而，非阻塞调用本质上是告诉内核“当你有一些新的数据或者这些连接中的任意一个有事件时才调用我”。这些非阻塞调用设计于高效地处理大量的I/O负载，以及减少上下文切换。&lt;/p>&lt;p>到目前为止你还在看这篇文章吗？因为现在来到了有趣的部分：让我们来看下一些流利的语言如何使用这些工具，并就在易用性和性能之间的权衡作出一些结论……以及其他有趣的点评。&lt;/p>&lt;p>请注意，虽然在这篇文章中展示的示例是琐碎的（并且是不完整的，只是显示了相关部分的代码），但数据库访问，外部缓存系统（memcache等全部）和需要I/O的任何东西，都以执行某些背后的I/O操作而结束，这些和展示的示例一样有着同样的影响。同样地，对于I/O被描述为“阻塞”（PHP，Java）这样的情节，HTTP请求与响应的读取与写入本身是阻塞的调用：再一次，更多隐藏在系统中的I/O及其伴随的性能问题需要考虑。&lt;/p>&lt;p>为项目选择编程语言要考虑的因素有很多。当你只考虑性能时，要考虑的因素甚至有更多。但是，如果你关注的是程序主要受限于I/O，如果I/O性能对于你的项目至关重要，那这些都是你需要了解的。“保持简单”的方法：PHP。&lt;/p>&lt;p>回到90年代的时候，很多人穿着匡威鞋，用Perl写着CGI脚本。随后出现了PHP，很多人喜欢使用它，它使得制作动态网页更为容易。&lt;/p>&lt;p>PHP使用的模型相当简单。虽然有一些变化，但基本上PHP服务器看起来像：&lt;/p>&lt;p>HTTP请求来自用户的浏览器，并且访问了你的Apache网站服务器。Apache为每个请求创建一个单独的进程，通过一些优化来重用它们，以便最大程度地减少其需要执行的次数（创建进程相对来说较慢）。Apache调用PHP并告诉它在磁盘上运行相应的&lt;code>.php&lt;/code>文件。PHP代码执行并做一些阻塞的I/O调用。若在PHP中调用了&lt;code>file_get_contents()&lt;/code>，那在背后它会触发&lt;code>read()&lt;/code>系统调用并等待结果返回。&lt;/p>&lt;p>当然，实际的代码只是简单地嵌在你的页面中，并且操作是阻塞的：&lt;/p>&lt;p>&lt;img data-s="300,640" data-type="png" data-src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" class="" data-ratio="0.45230263157894735" data-w="608" src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" data-fail="0">&lt;/p>&lt;p>关于它如何与系统集成，就像这样：&lt;/p>&lt;p>&lt;img data-src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" class="" data-ratio="1" data-w="1280" data-type="jpeg" src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" data-fail="0">&lt;/p>&lt;p>相当简单：一个请求，一个进程。I/O是阻塞的。优点是什么呢？简单，可行。那缺点是什么呢？同时与20,000个客户端连接，你的服务器就挂了。由于内核提供的用于处理大容量I/O（epoll等）的工具没有被使用，所以这种方法不能很好地扩展。更糟糕的是，为每个请求运行一个单独的过程往往会使用大量的系统资源，尤其是内存，这通常是在这样的场景中遇到的第一件事情。&lt;/p>&lt;p>注意：Ruby使用的方法与PHP非常相似，在广泛而普遍的方式下，我们可以将其视为是相同的。&lt;/p>&lt;h2>多线程的方式：Java&lt;/h2>&lt;p>所以就在你买了你的第一个域名的时候，Java来了，并且在一个句子之后随便说一句“dot com”是很酷的。而Java具有语言内置的多线程（特别是在创建时），这一点非常棒。&lt;/p>&lt;p>大多数Java网站服务器通过为每个进来的请求启动一个新的执行线程，然后在该线程中最终调用作为应用程序开发人员的你所编写的函数。&lt;/p>&lt;p>在Java的Servlet中执行I/O操作，往往看起来像是这样：&lt;/p>&lt;p>&lt;img data-s="300,640" data-type="png" data-src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" class="" data-ratio="0.3900804289544236" data-w="746" src="https://pangyd.com/uploads/2017/10/74c10f869f038762.jpg" data-fail="0">&lt;/p>&lt;p>由于我们上面的&lt;code>doGet&lt;/code>方法对应于一个请求并且在自己的线程中运行，而不是每次请求都对应需要有自己专属内存的单独进程，所以我们会有一个单独的线程。这样会有一些不错的优点，例如可以在线程之间共享状态、共享缓存的数据等，因为它们可以相互访问各自的内存，但是它如何与调度进行交互的影响，仍然与前面PHP例子中所做的内容几乎一模一样。每个请求都会产生一个新的线程，而在这个线程中的各种I/O操作会一直阻塞，直到这个请求被完全处理为止。为了最小化创建和销毁它们的成本，线程会被汇集在一起，但是依然，有成千上万个连接就意味着成千上万个线程，这对于调度器是不利的。&lt;/p></description></item><item><title>【励志】写给立志做码农的大学生</title><link>https://pangyd.com/post/100/</link><pubDate>Tue, 12 Sep 2017 19:30:31 +0800</pubDate><guid>https://pangyd.com/post/100/</guid><description>&lt;p>确定方向&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>选择比努力更重要。&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 关于方向的选择其实越早确定越好，生活中我们要面临无数个选择，前几天看的一个黑客相关的美剧中有句台词说的不错：&lt;/p>&lt;p>life is binary.&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 生活就是二进制，一个个0101组成的。每一次抉择，选了就是1，不选就是0。另外也有一句话说：“人一生要面临很多选择，但是真正能决定你命运的只有几个”。没错其实就是这样。&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 如果你是计算机专业的学生，那么到底是考研还是就业就是首先要面临的问题。本文是面向确定了毕业要工作的大学生的，所以关于这个抉择，不再赘述。&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 就业的话，本文标题是码农，实际是指所有计算机相关的技术工种。包括开发、测试、运维等。&lt;/p>&lt;p>很多选择本身并没有对错或优劣，只有适合不适合。&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 不要滥用勤能补拙，这个词语一度被很多人奉为圭臬，但同时成了枷锁。我相信这个词，但是要考虑现状，要考虑投资回报率。你在自己并不擅长或不感兴趣的领域深耕了四年，最后不一定能获得多少成绩。当然如果你能在毕业后继续深耕几年或许是可以的，但是我希望每一位大学生在毕业的时候都能有一份好的工作，并且如果你并不喜欢某一领域的话，那么我相信你一定不会坚持下去。所以我们一定要找到适合自己的方向！&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 那么如何发现自己对什么感兴趣呢？我也不知道很好的办法，我只知道一个朴素的方法——尝试。趁着年轻，就要多尝试。千万不要大三了都还不知道自己兴趣在哪，想做什么，适合什么。所以大一大二努力去碰钉子吧。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>算法还是开发？&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 数据结构和算法很重要，无论是面试还是工作，无论你从事哪方面的技术。不过算法虽然重要，但并不适合每个人都花费大学全部的精力去钻研。&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 相信很多学校都有ACM竞赛相关的社团或组织。很不幸，我们学校没有，我大一的时候也花了很多精力刷题，但是硬件条件不太允许，氛围太缺乏。如果你觉得自己能够在ACM比赛中游刃有余，那么恭喜你，你可以一心一意搞算法。如果你觉得自己在这个过程中十分吃力，挫败感频生，那么也不要气馁，或许有另一条路是属于你的。选择开发，有算法功底深厚是很棒的事，但是仅仅只有算法同样是不够的，计算机海洋还有很多未知等着你探索。&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 算法岗包括数据挖掘、机器学习之类的（怎么样，高大上吧，反正我不懂）。要说明的是想做算法的同学最好选择读研继续深造，因为大企业在算法岗的招聘上对本科生是很不友好的。还是要申明一句，你做开发也不能忽视算法和数据结构，起码面试还是经常考的！记住一句：&lt;/p>&lt;p>算法功底好的人，运气都不会差。&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 对于本科生而言做开发还是相对容易的一条道路，不过开发的技术路线也是不胜枚举：前端、后台（PHP后台、Java后台等等）、移动端（安卓和iOS）、游戏开发、数据库（比如做DBA）……。这里我肯定不会去推荐你去学哪一种，我没有能力也不适合。只有你自己才能发现自己的兴趣以及好奇心之所在。&lt;/p>&lt;p>我能做的只是在浩如烟海的技术观点中，帮一个个本科生排疑解惑。&lt;/p>&lt;p>认识技术&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 关于技术，很多本科生都存在诸多误区。初学者总喜欢追随牛逼的技术，实在过于盲目，找准自己的定位最重要。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>误区1： 图形化的东西比非图形化东西更牛逼&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 多见于初学者，尤其是计算机专业新生（我大一的时候就是）。当时学校教了点C语言，一直都是控制台程序，面对黑窗口，我就各种百度看看怎么弄出图形化的东西，那时候才知道GUI这个缩写是啥意思（当初知道这个缩写的全称还小激动了一下下，果然我还是太年轻了），然后知道了WIN32、MFC这些名词。确实只能说是知道名词。当时对着视频教程做了计算器，就是用VC++拖拖控件，视频里的人敲一句代码，我就敲一句。后面虽然弄出来了，但是感觉自己什么都不懂，只是依样画葫芦。这时我才意识到，还有很多基础没有打牢。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp; &amp;nbsp; 八卦一下，现在桌面客户端的开发工作并不多，所以大家谨慎选择这一技术方向。桌面端GUI技术一度火爆（MFC、Qt、WinForm、WPF、Swing……），但如今早已是互联网及移动互联网时代，所以大家真的要慎重选择。不过还是可以学习一下的，至少能加深你对编程语言以及设计模式的理解。&lt;/p></description></item></channel></rss>