前言
最近把从2017年就开始用的13寸乞丐版MacBookPro淘汰了。它是我打从学习编程开始就一直在用的电脑,到现在也有四年了,多少有点感情,但它实在是太卡了,因此,我不得不…… Continue reading...
最近把从2017年就开始用的13寸乞丐版MacBookPro淘汰了。它是我打从学习编程开始就一直在用的电脑,到现在也有四年了,多少有点感情,但它实在是太卡了,因此,我不得不…… Continue reading...
知乎问题:多路复用一样会阻塞用户线程,那它和同步阻塞有什么区别? - Twosee的回答:
有个叫@轩辕之风的答主用打电话和微信作比喻,让我觉得很有意思,所以作了这篇回答。
同步阻塞就是语音通话,一个人同时只能处理一个会话,对端不说话就是读阻塞,你说的太快对方听不过来就是写阻塞… 但是用短信作为多路复用的比喻让我感觉差了那么点意思,或许改成QQ微信聊天更佳,我斗胆扩写一下:
Continue reading...分享会上讲到了PHP的packed array 与 hash array 对比
1 | $array = []; |
output:
1 | string(11) "mem+=528480" |
本文是对「命名参数RFC」的个人解读,先让我们来简单看下RFC的主要内容:
命名参数特性允许基于参数名称而不是参数位置来传递参数,这使得:
初次接触Swoole的PHP开发者多少都会有点雾里看花的感觉,看不清本质。一部分PHP开发者并不清楚Swoole是什么,只是觉得很牛掰就想用了,这种行为无异于写作文的时候总想堆砌一些华丽的辞藻或是引经据典来提升文章逼格,却背离了文章的主题,本末倒置,每一种技术的诞生都有它的原因,异步或是协程不是万能的银弹,你需要它的时候再去用它,而不是想用它而用它,毕竟编程世界的惯性是巨大的,这天下还是同步阻塞的天下。还有一部分开发者是对Swoole有了一些自己的见解,但对错参半,写出来的程序能跑,甚至也能上生产,但不是最优的,其中大部分问题都源于开发者无法将惯有的思维方式灵活转变。
Continue reading...作者:陈曹奇昊
首发于公众号: 学而思网校技术团队
一丶 什么是FastCGI
在Swoole最新发布的v4.5(RC)版本中,我们实现了一项非常有意思的新特性,那就是协程版本的FastCGI客户端。
那么什么是FastCGI呢?首先先来一个官方解释:
快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。
其实很简单,大家使用PHP-FPM搭建服务的时候必然少不了前面架一个Nginx丶Apache或者IIS之类的东西作为代理,我们应用程序和代理通信的时候,可能会使用各种各样的协议(常见的比如浏览器使用的是HTTP/1.1,HTTP2,QUIC等),而代理的职责就是把各种协议的请求翻译成FastCGI来和PHP-FPM通信,这样PHP服务就无需关心各种类型协议的解析,而可以只关心处理请求本身的内容,且FastCGI是二进制协议,相较于HTTP1.x这样的文本协议,FastCGI可以说是非常高效。
实现了FastCGI客户端,那么我们就可以直接与PHP-FPM服务进行交互,但是这有什么用呢?
Continue reading...这是一篇很久以前写的文章(大概是两年前),一直没发,可能囿于技术水平,有一些错误,已经草草修正了一些内容,如仍有写歪来的地方,欢迎拍砖。
我们每天都在和变量打交道,PHP的变量足够简单,当静态语言的初学者还在将类型推导(如C++写”auto foo = 1”将自动推导foo为int类型)惊奇不已的时候,动态语言的开发者早已习以为常了。
但天下没有白吃的午餐,变量使用起来越方便,背后的原理就越复杂,你以为你已经能将变量运用自如,但其实你只是个会开车的普通司机,你并不懂车。而你若想要成为PHP世界的专业级赛车手,赛车的每个零部件到组装到核心引擎的运转,你都必须了如指掌。
Continue reading...2020更新:扩展对象使用“属性”来存储东西不是一个好的行为,我们可能需要花费很大代价来阻止来自PHP用户的破坏,至于更好的存储方法,我会在未来的文章中讲到
zend_read_property
返回了什么, 其实我从前也未深究, 它的返回值类型是一个zval *
, 所以很理所当然的, 大家都会认为如果获取了一个不存在的属性, 它的返回值就是NULL
.
比如zend_hash_str_find
这个API, 它会从HashTable
里寻找对应的bucket, 然后获取它的值, 如果这个值不存在, 就返回NULL.
而且我们清楚, 不管是array
, 还是object
的properties
, 都是用HashTable
来存储的, 那么不存在的时候返回NULL
, 也是理所当然.
这里还要注意一点, 我所指的不存在, 是在HashTable
里没有这个bucket, 举个例子:
1 | $foo = ['bar' => null]; |
这样可以很清楚的发现区别了, 在置一个键为null
的时候, 实际上是在这个bucket
上放了一个type = null
的zval
, 而当使用unset
的时候, 才是真正的把这个bucket
从HashTable
上删去了, 也就是说这个键和存储键值的容器都不存在了. 所以unset
真是个很暴力的连根拔除的操作.
unset
的开销会比赋值null
更大, 因为它删去属性的同时, 可能会触发数组结构重置, 这个问题在用SplQueue
和array_push/pop
对比的时候显而易见.
事情是这样的, 最近在做Swoole的Websocket的底层代码优化, 和编写更多的单元测试来保证代码正确和功能的稳定性, 写了很多高质量的”混沌”测试, 好吧, 其实并不是那么混沌, 只是这个词眼看起来很帅.
以往的unit tests更像是一些带着assert的examples, 加之phpt的测试风格, 顶多再来个EXPECT(F/REGEX)的预期输出对比, 只能测试出这个功能能否跑通, 并没有覆盖到功能的健壮性.而每当底层出现BUG接着我们很快就发现了原因时, 都会感叹单元测试不够全面和完善.
所以在新写的测试中, 我尽量引入随机数据和一定量的并发压力来简单的模拟各种情况, 在自动化的单元测试中这样的做法已经是权衡了测试敏捷和健全的最优解了, 比如以下这个名为websocket-fin
的测试:
1 | $count = 0; |
研究这个主要是为了解决swoole-socket
模块的一个coredump的bug, 之前swoole采用了swoole_get/set_object
等做法来存取对应的对象, 只有socket模块使用了魔改zend_object的方法, 但是PHP7里用了比较hack的结构体技巧, 导致了一系列问题, 想魔改zend_object, 需要一番操作, 中文文档很难找到用法的, 都是一笔带过, 需要去看英文文档.
虽然只有一次提交, 但其实改了不下几十遍, 在此记录一下:
Swoole在socket coro
中使用了别的模块没有用到的自定义zend_object属性的技巧, 但是PHP7中它需要做额外的处理, 导致了一些问题.
因为 zend_object
在存储属性表时用了结构体 hack 的技巧,zend_object
尾部存储的 PHP 属性会覆盖掉后续添加进去的内部成员。所以 PHP7 的实现中必须把自己添加的成员添加到标准对象结构的前面:
1 | struct custom_object { |
不过这样也就意味着现在无法直接在 zend_object* 和 struct custom_object* 进行简单的转换了,因为两者都一个偏移分割开了。所以这个偏移量就需要被存储在对象 handler 表中的第一个元素中,这样在编译时通过 offsetof() 宏就能确定具体的偏移值
Continue reading...大概是在一个月前了…那时候刚开始给swoole contribute代码, 初生牛犊, 修了不少小bug, 最后某位仁兄贴了个issue说swoole的mysql-client搞不掂存储过程, 当时我想想, 存储过程这东西实在没什么用, 甚至在很多大公司开发手册上是禁止使用的(某里粑粑), 具体的 为什么不要使用存储过程 戳这里, 但是考虑到一个作为一个底层扩展, 各种用户都有, rango就给我分配了这个任务, 于是我就马上进行了一番研究.
其实内容当时在PR里都贴了, https://github.com/swoole/swoole-src/pull/1688, 现在在博客补个票
完整的MySQL存储过程支持
做了以下几件事:
一开始先想着和PDO一样给Swoole做一个fetch模式
1 | ['fetch_mode' => true] //连接配置里加入这个 |
1 | $stmt = $db->prepare('SELECT `id` FROM `userinfo` LIMIT 2'); |
前一部分内容抄自振宇哥的博客: 旷绝一世, 在此基础后续扩写一部分
我们在写扩展的时候很常见的这样的宏,就比如swoole扩展中:
1 | ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_listen, 0, 0, 3)//名字,unused,引用返回,参数个数 |
这个宏组合是用来定义函数的参数,我们不妨去跟下ZEND_BEGIN_ARG_INFO_EX
与ZEND_END_ARG_INFO
的定义。
定义在zend_API.h文件中,ZEND_BEGIN_ARG_INFO_EX
的定义为:
1 |
ZEND_END_ARG_INFO的定义为:
1 |
那么组合起来变成c代码就是
1 | static const zend_internal_arg_info arginfo_swoole_server_listen[] = { \ |
sudo apt-get install -y build-essential
sudo apt-get install -y libxml2-dev
sudo apt-get install -y libpcre3-dev
sudo apt-get install -y libjpeg62-dev
烧水是一件很神奇的事情, 首先有这么一个家喻户晓的传说故事:
“瓦特小的时候,看见炉子上壶里的水沸腾了。蒸汽把壶盖顶了起来,瓦特从中受到启发,长大后发明了蒸汽机,成为著名的发明家。”
当然,真实的蒸汽机的真正意义上发明也是类似的, “约1679年法国物理学家丹尼斯·巴本在观察蒸汽冒出他的高压锅后制造了第一台蒸汽机的工作模型”。后来,人类进入了蒸汽时代。
直到今天都没有找到能够替代”烧开水”获取能源的方案,这个有意思的概念来源于一个知乎问题人类的能源大多都是靠烧开水,这种说法正确吗?,最后得出的结论是:我们寿命内,可用的能源主要来源靠烧水。
Continue reading...[TOC]
MySQL客户端与服务器的交互主要分为两个阶段:握手认证阶段和命令执行阶段。
握手认证阶段为客户端与服务器建立连接后进行,交互过程如下:
客户端认证成功后,会进入命令执行阶段,交互过程如下:
命令: show processlist;
如果是root帐号,你能看到所有用户的当前连接。如果是其它普通帐号,只能看到自己占用的连接。show processlist
只列出前100条
如果想全列出请使用**show full processlist;
**
1 | mysql> show processlist; |
命令: show status;
命令:show status like '%下面变量%';
众所周知, PHP是由C语言编写的, 扩展也不例外, Swoole又是PHP扩展中发展的比较快且很权威的一个扩展, 对于MySQL这部分模块的浅析, 暂可不必了解Swoole底层的实现, 而先关注应用层面的实现.
所以除了PHP我们仅需了解以下几个方面的知识:
而使用过Swoole的同学一定对以下工具不陌生:
GDB
(Mac下用LLDB
)和Valgrind
作为源码/内存分析Wireshark
或TcpDump
作为网络分析本文原文来源自 http://www.cnblogs.com/zichi/p/4792589.html
相关内容经过整理, ABCD几个水果单词更加容易对应起来
前面我们已经了解了六大位操作符(&
|
~
^
<<
>>
)的用法(javascript 位运算),也整理了一些常用的位运算操作(常用位运算整理),本文我们继续深入位运算,来了解下二进制的经典应用-标志位与掩码。
位运算经常被用来创建、处理以及读取标志位序列——一种类似二进制的变量。虽然可以使用变量代替标志位序列,但是这样可以节省内存(1/32)。
例如有4个标志位:
标志位通过位序列DCBA来表示,当一个位置被置为1时,表示有该项,置为0时,表示没有该项。例如一个变量flag=9,二进制表示为1001,就表示我们有D和A。
掩码 (bitmask) 是一个通过与/或来读取标志位的位序列。典型的定义每个标志位的原语掩码如下:
1 | var FLAG_A = 1; // 0001 |
许多人用shell脚本完成一些简单任务,而且变成了他们生命的一部分。不幸的是,shell脚本在运行异常时会受到非常大的影响。在写脚本时将这类问题最小化是十分必要的。本文中我将介绍一些让bash脚本变得健壮的技术。
你因为没有对变量初始化而使脚本崩溃过多少次?对于我来说,很多次。
1 | chroot=$1 |
如果上面的代码你没有给参数就运行,你不会仅仅删除掉chroot中的文档,而是将系统的所有文档都删除。那你应该做些什么呢?好在bash提供了set -u,当你使用未初始化的变量时,让bash自动退出。你也可以使用可读性更强一点的set -o nounset
。
1 | bash /tmp/shrink-chroot.sh |
前几天在计划写一个爬虫脚本时, 由于涉及到html的浏览器渲染, 干脆用就用浏览器和控制台运行js脚本来作为爬虫工具, chrome支持ES6语法(有些需要在dev设置中开启), 写起来也是十分舒服, 爬完数据并处理过后通过xhr扔给后端服务器即可, 后端是用Swoole负责接收并向数据库进行大文本插入, 不幸的是在这时候错误出现了.
在数千个请求后nginx代理的后端挂掉了,返回了502BadGateWay,肯定要去上游找原因了,由于swoole是跑在docker容器中的, 于是马上查看容器日志
1 | $ docker logs custed_swoole_1 --tail 100 |
可以看到如下报错
1 | $ WARNING swProcessPool_wait: worker#0 abnormal exit, status=0, signal=11 |
google了一下没找到相关问题, 只能请教rango, 说是signal11是coredump了, 让我抓一下core文件
然后就开始踩坑了, 我的服务是运行在docker中的, docker里要抓core文件需要一波操作了…
废话不多说直接总结一下坑
没有特权模式, 容器里就无法使用gdb调试
我用的是docker-compose 所以配置里需要加这么一行
1 | privileged: true |
如果是run的话, 加:
1 | --privileged |
因此,在PHPDoc中,可以在成员变量声明之上指定@var
来提示其类型。然后一个IDE,例如PHPEd将知道它正在使用什么类型的对象,并且能够为该变量提供代码洞察。
1 |
|
这样做很好,直到我需要对一组对象做同样的事情,以便在以后迭代这些对象时才能获得正确的提示。
那么,有没有办法声明一个PHPDoc标签来指定成员变量是SomeObj
的数组? @var
数组是不够的,例如@var array(SomeObj)
似乎没有效果。
在JetBrains的PhpStorm IDE中,您可以使用/** @var SomeObj[] */
,例如:
1 | /** |
phpdoc documentation推荐这种方法:
Continue reading...specified containing a single type, the Type definition informs the reader of the type of each array element. Only one Type is then expected as element for a given array.
Example:
@return int[]
SQL报错注入就是利用数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。这种手段在联合查询受限且能返回错误信息的情况下比较好用,毕竟用盲注的话既耗时又容易被封。
MYSQL报错注入个人认为大体可以分为以下几类:
下面就针对这几种错误类型看看背后的原理是怎样的。
Continue reading...The 2018 Guide to Building Secure PHP Software!
2018 年将至,一般程序员(特别是 Web 开发程序员)应当抛弃过去开发PHP程序的很多不好的习惯和观念了。虽然部分人不以为意,但是这确实是事实。
这个指南应该以重点部分作为 PHP: The Right Way 安全章节的补充,而不是以一般的 PHP 编程话题。
请在 2018 年使用 PHP 7.2, 并且计划 2019 年初切换到 PHP 7.3。
PHP 7.2 已于 2017 年 11 月 30 日发布。
写这篇文章的时候,只有 7.1 和 7.2 版本还在被 PHP 官方积极维护,而 5.6 和 7.0 只在大概1年内提供安全补丁更新。
对于其他官方不维护的 PHP 版本,虽然某些操作系统会提供长期支持和维护,但这其实通常是有害的。尤其是他们提供安全支持补丁却没有版本号,这使得很难解释系统的安全性(仅仅知道 PHP 版本)。
因此,无论其他供应商提出了什么承诺,如果可以,你就应该在任何时候都坚决地使用官方提供支持的 PHP 版本。这样,尽管最终是一个短暂的安全版本,但一个不断致力于升级的版本,总会让你收获一些意外的惊喜。
Continue reading...以Swoole服务事件回调为例
1 | $server->on('Request', function ($req, $resp) { |
1 | class A { |
1 | function my_onRequest($req, $resp){ |
1 | class A { |
常规的编程入门有“Hello world”程序,而深度学习的入门程序则是MNIST,一个识别28×28像素的图片中的手写数字的程序。
备注:MNIST 的数据和官网
深度学习的内容,其背后会涉及比较多的数学原理,作为一个初学者,受限于我个人的数学和技术水平,也许并不足以准确讲述相关的数学原理,因此,本文会更多的关注“应用层面”,不对背后的数学原理进行展开,感谢谅解。
Continue reading...2017年围棋界发生了一件比较重要事,Master(Alphago)以60连胜横扫天下,击败各路世界冠军,人工智能以气势如虹的姿态出现在我们人类的面前。围棋曾经一度被称为“人类智慧的堡垒”,如今,这座堡垒也随之成为过去。从2016年三月份AlphaGo击败李世石开始,AI全面进入我们大众的视野,对于它的讨论变得更为火热起来,整个业界普遍认为,它很可能带来下一次科技革命,并且,在未来可预见的10多年里,深刻地改变我们的生活。
Continue reading...12月23日,由开源中国联合中国电子技术标准化研究院主办的2017源创会年终盛典在北京万豪酒店顺利举行。作为年末最受期待的开源技术分享盛会,国内顶尖技术大拿、知名技术团队、优秀开源项目作者,及近1000名技术爱好者共聚一堂,探讨最前沿、最流行的技术话题和方向,推动国内开源创新体系发展,共建国内开源生态标准。PHP7 已发布近两年, 大幅的性能提升使得 PHP 的应用场景更加广泛,刚刚发布的 PHP7.2 相比 PHP7.1 又有了近 10% 的提升。在本次大会上,链家集团技术副总裁、PHP 开发组核心成员鸟哥发表了以 “ PHP Next: JIT ”为主题的演讲,分享了 PHP 的下一个性能提升的主要举措:JIT 的进展, 以及下一个大版本的 PHP 可能的特性。他表示,JIT 相比 PHP7.2 ,在一些场景可以达到三倍,但由于 JIT 的核心前提是类型推断,得到的信息越多效果越好,因此也容易受到限制。 JIT 发布后,随着更优秀的代码出现,性能提升会更明显。
惠新宸 ,国内最有影响力的PHP技术专家, PHP开发组核心成员 , PECL开发者 , Zend公司外聘顾问, 曾供职于雅虎,百度,新浪。现任链家集团技术副总裁兼总架构师。PHP 7 的核心开发者,PHP5.4,5.5的主要开发者。也是Yaf (Yet another framework),Yar(Yet another RPC framework) 以及Yac(Yet another Cache)、Taint等多个开源项目的作者,同时也是APC,Opcache ,Msgpack等项目的维护者。
PHP Next: JIT
Continue reading...鸟哥本次分享的主要内容是,在php7发布的这两年期间他们的主要工作,包括release的7.1和正在开发中的jit分支。说实话,由于本人水平有限,鸟哥分享的内容只能大概听懂意思,知道他们在做什么,但具体原理细节,鸟哥分享的我还真听不懂。这里就对鸟哥的分享内容做个总结。
php7于15年正式发布,他的最大卖点是,无感知的100%性能提升,包含了运行速度与内存消耗。那么在此之后php该往哪里发展呢?目前已经在开发的一个大方向就是JIT
JIT是什么?为什么是JIT?
鸟哥并没有做过多的解释。我就谈一些我的肤浅认识,给phper们提供些参考。
首先JIT(just in time)并非是新技术,一大批语言如java早已实现。JIT的思想很简单,即在程序运行时动态对程序进行编译,生成平台相关的机器码,从而加快程序运行速度。
php文件的执行流程大致是首先引擎加载php文件,解释器逐条解释执行代码。引入JIT后,前面一样,重点是JIT编译器会根据Runtime信息对热点代码进行动态编译生成机器码,然后这部分代码以后就可以直接执行了,而不需要解释器逐条解释执行了,运行效率便得到了提升
看到这里不知道大家是否和我有一样的疑问,既然编译为机器码执行的效率那么高,为何不在项目正式部署前全部进行编译,何必在运行时编译?
要知道运行时编译也会增加程序的执行时间的。我在查阅了一些资料和一番思考后,有以下一些浅见
代码发布前先编译,是比JIT更早的通用办法,称为AOT(ahead of time)
,c语言便是这种执行模式。关于这两种模式孰优孰劣,学术界一直争论不休,目前也没有定论。但JIT相比AOT有这样几个优点
基于以上几个优点,再结合php一贯的简单易用原则,我想JIT确实是不错的选择。不过php也是支持AOT的,有兴趣的同学可以查一下。
Continue reading...有些驱动不支持或有限度地支持本地预处理。使用此设置强制PDO总是模拟预处理语句(如果为 TRUE ),或试着使用本地预处理语句(如果为 FALSE)。如果驱动不能成功预处理当前查询,它将总是回到模拟预处理语句上。 需要 bool 类型。
PDO::ATTR_EMULATE_PREPARES 启用或禁用预处理语句的模拟。
这是之前我说的默认总是模拟prepare,因为低版本MYSQL驱动不支持prepare.
数据类型问题,在旧版本的MySQL中还真是不能解决的。它直接返回字符串给外部系统。稍微新一点的MySQL和客户端驱动可以直接内部的本地类型而不再进行内部转换为字符串了。有了这个基础,就有解决的可能了。
此处用query测试证明,prepare_excute二连也是一样的
1 | $db = new \PDO('mysql:dbname='.$options['database'].';host='.$options['host'], $options['user'], $options['password']); |
1 | array(2) { |
此外,PDO为参数绑定也提供了强类型的设定,默认传给Mysql的是string,常用的类型如下:
1 | $data_types = [ |
Continue reading...data_type: 使用PDO :: PARAM_ * 常量来设定参数的显式数据类型。要从存储过程返回INOUT参数,请使用按位或运算符来设置
data_type
参数的PDO :: PARAM_INPUT_OUTPUT位。
本文转载自 cizixs
经常听到有人说磁盘很慢、网络很卡,这都是站在人类的感知维度去表述的,比如拷贝一个文件到硬盘需要几分钟到几十分钟,够我去吃个饭啦;而从网络下载一部电影,有时候需要几个小时,我都可以睡一觉了。
最为我们熟知的关于计算机不同组件速度差异的图表,是下面这种金字塔形式:越往上速度越快,容量越小,而价格越高。这张图只是给了我们一个直观地感觉,并没有对各个速度和性能做出量化的说明和解释。而实际上,不同层级之间的差异要比这张图大的多。这篇文章就让你站在 CPU 的角度看这个世界,说说到底它们有多慢。
希望你看到看完这篇文章能明白两件事情:磁盘和网络真的很慢,性能优化是个复杂的系统性的活。
Continue reading...