PHP程序员-常用工具
三连问经常有社区的同学问: “我的PHP程序有没有阻塞,我的PHP程序有没有开启协程(对自己写好的代码表示不自信),我的PHP程序有没有问题”.然后贴出了自己的程序,然后进入了愉快的灌水环节,随着时间的流逝,我们并没有形成系统的解决方法.求人不如求己,我们自己来解决这些问题. 方法论最近接触到一个牛X的名词-方法论.
我们PHP程序员是不是也可以有一个方法,解决一些很容易碰到的基础问题.借这个平台抛砖引玉,希望大家多多指教.
我是谁
PHP是一个解释型的语言,我们首先要上来看看自己的执行的PHP在哪里,是什么,以免在陌生的机器上一顿操作猛如虎才发现没对上号,比如笔者的机器上装了好多个版本的PHP.不要笑话这个问题,真的有不少人工作几年忽略了这个问题.直到他某一天在这个上面浪费了两小时….(逃 1 $ which php 2 /home/shiguangqi/bin/php 3 $ ll /home/shiguangqi/bin/php 4 lrwxrwxrwx 1 shiguangqi shiguangqi 30 10月 25 12:09 /home/shiguangqi/bin/php -> /usr/local/php-7.2.14//bin/php* PHP安装的版本,加载了什么配置文件,PHP的编译参数是什么,有没有你关注的扩展被加载,加载的配置是什么版本等一系列问题. 1 $ php -v 2 PHP 7.2.14 (cli) (built: Jul 4 2019 11:02:01) ( NTS DEBUG ) 3 Copyright (c) 1997-2018 The PHP Group 4 Zend Engine v3.2.0,Copyright (c) 1998-2018 Zend Technologies 加载什么配置 1 $ php --ini 2 Configuration File (php.ini) Path: /usr/local/php-7.2.14/lib 3 Loaded Configuration File: /usr/local/php-7.2.14/lib/php.ini 4 Scan for additional .ini files in: (none) 5 Additional .ini files parsed: (none) 编译参数, 我这个版本是debug版本,默认静态编译了这些模块. 1 $ php -i | grep configure 2 Configure Command => './configure' '--prefix=/usr/local/php-7.2.14' '--with-config-file-path=/usr/local/php-7.2.14/lib' '--with-mysqli=mysqlnd' '--with-jpeg-dir' '--with-png-dir' '--with-iconv-dir' '--with-freetype-dir' '--with-zlib' '--with-mhash' '--with-libxml-dir' '--with-curl' '--with-mcrypt' '--with-gd' '--with-openssl' '--enable-ftp' '--enable-xml' '--enable-bcmath' '--enable-gd-native-ttf' '--enable-mbregex' '--enable-mbstring' '--enable-pcntl' '--enable-sockets' '--enable-fpm' '--enable-soap' '--enable-zip' '--enable-debug' 查看PHP扩展相关,其实可以通过 php --ri swoole 我要干啥
这一部分对于我们来说最熟悉不过,我们每天干的就是这个事情. 1 <?php 2 $redis = new Redis; 3 $redis->connect("127.0.0.1",6379); 4 $var = $redis->get("key"); 5 var_dump($var); 6 <?php 7 SwooleRuntime::enableCoroutine(); 8 go(function () { 9 $redis = new Redis; 10 $redis->connect("127.0.0.1",6379); 11 $var = $redis->get("key"); 12 var_dump($var); 13 }); 然后我们愉快的得出了同样的结果. 干的咋样
得出结果很容易,问题是我们干的质量怎么样呢,上面的例子只是类比,大家不要耻笑这两个例子太简单. 1 strace -s 1000 php redis.php 2 socket(AF_INET,SOCK_STREAM,IPPROTO_IP) = 3 3 fcntl(3,F_GETFL) = 0x2 (flags O_RDWR) 4 fcntl(3,F_SETFL,O_RDWR|O_NONBLOCK) = 0 5 connect(3,{sa_family=AF_INET,sin_port=htons(6379),sin_addr=inet_addr("127.0.0.1")},16) = -1 EINPROGRESS (Operation now in progress) 6 poll([{fd=3,events=POLLIN|POLLOUT|POLLERR|POLLHUP}],1,60000) = 1 ([{fd=3,revents=POLLOUT}]) 7 getsockopt(3,SOL_SOCKET,SO_ERROR,[0],[4]) = 0 8 fcntl(3,O_RDWR) = 0 9 setsockopt(3,SOL_TCP,TCP_NODELAY,[1],4) = 0 10 setsockopt(3,SO_KEEPALIVE,4) = 0 11 poll([{fd=3,events=POLLIN|POLLPRI|POLLERR|POLLHUP}],0) = 0 (Timeout) 12 sendto(3,"*2rn$3rnGETrn$3rnkeyrn",22,MSG_DONTWAIT,NULL,0) = 22 13 poll([{fd=3,0) = 0 (Timeout) 14 poll([{fd=3,events=POLLIN|POLLERR|POLLHUP}],revents=POLLIN}]) 15 recvfrom(3,"$6rnvalue2rn",8192,NULL) = 12 16 write(1,"string(6) "",11string(6) ") = 11 17 write(1,"value2",6value2) = 6 我们还可以加上一些参数,得到更详细的数据,当前系统调用的消耗的时间和当前时间戳 1 $ strace -ttt -T -s 1000 php redis.php 2 1572266793.054360 socket(AF_INET,IPPROTO_IP) = 3 <0.000013> 3 1572266793.054389 fcntl(3,F_GETFL) = 0x2 (flags O_RDWR) <0.000007> 4 1572266793.054414 fcntl(3,O_RDWR|O_NONBLOCK) = 0 <0.000008> 5 1572266793.054438 connect(3,16) = -1 EINPROGRESS (Operation now in progress) <0.000070> 6 1572266793.054533 poll([{fd=3,revents=POLLOUT}]) <0.000008> 7 1572266793.054565 getsockopt(3,[4]) = 0 <0.000008> 8 1572266793.054594 fcntl(3,O_RDWR) = 0 <0.000006> 9 1572266793.054619 setsockopt(3,4) = 0 <0.000008> 10 1572266793.054644 setsockopt(3,4) = 0 <0.000007> 11 1572266793.054689 poll([{fd=3,0) = 0 (Timeout) <0.000007> 12 1572266793.054717 sendto(3,0) = 22 <0.000030> 13 1572266793.054788 poll([{fd=3,0) = 1 ([{fd=3,revents=POLLIN}]) <0.000007> 14 1572266793.054816 recvfrom(3,"$",MSG_PEEK,NULL) = 1 <0.000009> 15 1572266793.054851 poll([{fd=3,revents=POLLIN}]) <0.000007> 16 1572266793.054878 recvfrom(3,NULL) = 12 <0.000009> 17 1572266793.054923 write(1,11string(6) ") = 11 <0.000010> 18 1572266793.054951 write(1,"value2",6value2) = 6 <0.000009> 19 1572266793.054977 write(1,""n",2" 我们就可以逐行查看程序系统调用的详情.很容易发现,这个程序是阻塞的,虽然每个系统调用的时间极短.但换个业务,换个依赖可就不是这样.但万变不离其宗. 我们再来看第二个程序,也就是开启协程后的系统调用 1 1572266985.463011 socket(AF_INET,SOCK_STREAM|SOCK_CLOEXEC,IPPROTO_IP) = 4 <0.000016> 2 1572266985.463048 fcntl(4,F_GETFL) = 0x2 (flags O_RDWR) <0.000006> 3 1572266985.463070 fcntl(4,O_RDWR|O_NONBLOCK) = 0 <0.000006> 4 1572266985.463092 setsockopt(4,4) = 0 <0.000007> 5 1572266985.463127 setsockopt(4,4) = 0 <0.000005> 6 1572266985.463167 connect(4,16) = -1 EINPROGRESS (Operation now in progress) <0.000076> 7 1572266985.463296 epoll_ctl(3,EPOLL_CTL_ADD,4,{EPOLLOUT,{u32=4,u64=38654705668}}) = 0 <0.000011> 8 1572266985.463353 epoll_wait(3,[{EPOLLOUT,u64=38654705668}}],4096,60000) = 1 <0.000007> 9 1572266985.463383 epoll_ctl(3,EPOLL_CTL_DEL,NULL) = 0 <0.000008> 10 1572266985.463407 getsockopt(4,[4]) = 0 <0.000008> 11 1572266985.463445 setsockopt(4,4) = 0 <0.000007> 12 1572266985.463467 setsockopt(4,4) = 0 <0.000007> 13 1572266985.463525 recvfrom(4,0x7f29bb9b033d,NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.000008> 14 1572266985.463556 sendto(4,0) = 22 <0.000033> 15 1572266985.463633 recvfrom(4,NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.000006> 16 1572266985.463662 recvfrom(4,NULL) = 12 <0.000007> 17 1572266985.463713 write(1,11string(6) ") = 11 <0.000009> 18 1572266985.463740 write(1,6value2) = 6 <0.000008> 可以发现,通过创建socket,然后connect操作,然后通过epoll_ctl加入监听,是通过多路复用的方式,这里是没有阻塞等待的,我们可以通过这种方式明确的确认自己的程序细节. 1 <?php 2 SwooleRuntime::enableCoroutine(); 3 go(function () { 4 $redis = new Redis; 5 $redis->connect("127.0.0.1",6379,0.5); 6 $var = $redis->get("key"); 7 var_dump($var); 8 }); (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |