PHP 获取 Linux 系统 CPU 负载的例子
最近使用 PHP 做了一个服务器负载监控的小东西,在服务器上使用 Workerman 开一个 WebSocket 服务,然后在浏览器中连接到服务。服务每隔 10 秒读取一次主机的相关信息,然后发送给客户端,客户端进行图形化显示。
总体的思路就是使用 PHP 调用 shell 命令,然后解析命令的输出内容。在获取 CPU 负载的时候,遇到了一些小问题。直观来说,直接使用 vmstat 命令就可以获取 CPU 负载,但是实际上,vmstat 命令第一行输出的从主机启动以来的平均 CPU 负载,并不是当前的负载。vmstat 命令还有一些参数,比如可以增加一个延迟参数 delay: vmstat 1,表示每秒输出一次数据,直到用户终止命令:
miroot@miserver:~$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
4 0 0 493644 162940 5727744 0 0 2 15 0 0 1 0 99 0
0 4 0 568392 162952 5656868 0 0 112 15584 8807 4496 29 6 57 7
3 0 0 567152 162952 5657416 0 0 40 116 10104 5164 28 6 65 2
2 1 0 566368 162956 5658476 0 0 84 22220 11126 5632 29 7 58 5
2 2 0 563320 162964 5659200 0 0 56 49240 9765 4792 21 7 53 19
0 0 0 566464 162976 5659892 0 0 80 1212 9998 5135 26 6 59 9
2 0 0 565400 162984 5660736 0 0 92 120 9288 4954 29 5 66 1
^C
miroot@miserver:~$
第一行数据是平均负载,从第二行数据开始,是当前的负载情况。作为监控来讲,肯定更加关注当前的负载情况。
那么,使用 PHP 调用 vmstat,当然不能使用延迟的方式来等待后续行的输出。
查了一些文档,发现在 Linux 上,系统负载的情况在 /proc/stat 这个文件中,这个文件中的内容比较多,所以我们换一个思路,采用 vmstat -s 的方式直接输出内容:
miroot@miserver:~$ vmstat -s
8165768 K total memory
4600664 K used memory
1980464 K active memory
2249908 K inactive memory
3565104 K free memory
232532 K buffer memory
2972048 K swap cache
8378364 K total swap
253352 K used swap
8125012 K free swap
1170373 non-nice user cpu ticks
25184 nice user cpu ticks
294692 system cpu ticks
1309152182 idle cpu ticks
1867039 IO-wait cpu ticks
566 IRQ cpu ticks
76405 softirq cpu ticks
0 stolen cpu ticks
4601555 pages paged in
96400000 pages paged out
1516 pages swapped in
67468 pages swapped out
243751059 interrupts
384963258 CPU context switches
1455419401 boot time
184668 forks
miroot@miserver:~$
可以看到,这里面包含很多和 CPU 相关的数据,实际上这个数据的来源就是 /proc/stat 文件。那么我们关心这么几项数据:
1170373 non-nice user cpu ticks
25184 nice user cpu ticks
294692 system cpu ticks
1309152182 idle cpu ticks
通过 man 5 proc 找到关于 /proc/stat 文件的说明,我们关心的是 CPU 相关数据的说明:
The amount of time, measured in units of USER_HZ (1/100ths of a second on most architectures, use sysconf(_SC_CLK_TCK) to obtain the right value), that the system spent in various states:
user (1) Time spent in user mode.
nice (2) Time spent in user mode with low priority (nice).
system (3) Time spent in system mode.
idle (4) Time spent in the idle task. This value should be USER_HZ times the second entry in the /proc/uptime pseudo-file.
大概的意思就是说,这些数值都是以 USER_HZ 为单位的。不管什么单位,总之他们的单位是一致的,那么我们就可以通过 2 次 vmstat -s 命令的输出来计算每个项上的增量,然后 4 个项上的增量相加就是总体的增量(其实后面还有更多关于 CPU 的数据,我们先忽略掉),然后计算每个项上的增量和总体增量的比,就是在这两次采样之间 CPU 在用户、系统和闲置状态下的负载。
参考代码如下:
// 在 Linux 系统上,需要使用 2 次 vmstat -s
// 结果的差值来计算两次采样之间的 CPU 占用比例
$last_cpu_ticks = array(
0, // non-nice user cpu ticks
0, // nice user cpu ticks
0, // system cpu ticks
0 // idle cpu ticks
);
function _get_cpu_status_linux()
{
global $last_cpu_ticks;
$s = shell_exec('vmstat -s | grep cpu');
if ($s === false) return false;
$lines = explode("n", $s);
if (count($lines) < 4) return false;
$current_data = array();
for ($i = 0; $i < 4; $i++)
{
$current_data[] = (int)(explode(' ', trim($lines[$i]))[0]);
}
$ret = array('user' => 0, 'sys' => 0, 'idle' => 0);
if ($last_cpu_ticks[0] > 0)
{
$total_delta = 0;
foreach ($current_data as $i => $v)
$total_delta += ($v - $last_cpu_ticks[$i]);
$ret['user'] = (int)(($current_data[0] - $last_cpu_ticks[0] + $current_data[1] - $last_cpu_ticks[1]) / $total_delta * 100);
$ret['sys'] = (int)(($current_data[2] - $last_cpu_ticks[2]) / $total_delta * 100);
$ret['idle'] = (int)(($current_data[3] - $last_cpu_ticks[3]) / $total_delta * 100);
}
for ($i = 0; $i < 4; $i++)
$last_cpu_ticks[$i] = $current_data[$i];
return $ret;
}
做一个代码发布的系统,需要用到PHP的exec函数来执行Linux下的命令和git,svn命令,如何判断PHP的exec函数是否执行成功呢?
写个PHP文件来做实验:
exec函数解析
exec语法: string exec(string command, string [array], int [return_var]);
exec返回值: 字符串
Exec参数说明
Command – 需要执行的命令
Array – 是输出值
return_var –是返回值0或1,如果返回0则执行成功,返回1则执行失败。
exec函数第一个参数是执行的命令,第二个参数是执行的结果,第三个参数是执行的状态。
<?php
exec('ls', $log, $status);
print_r($log);
print_r($status);
echo PHP_EOL;
执行这个php文件:
这里$log,$status输出结果如图。
但是$status为0,给人的感觉是执行失败,其实不是,这是exec执行成功。
改一下这个php文件,给exec第一个参数一个错误的命令。
如:exec(‘lsaa’,$log,$status).
再次执行,运行结果如图:
这里$status确是有值的。
那么证明$status为0的时候表示exec执行是成功的。这里PHP官方手册上并没有明确说明。
最终这个执行命令的方法如下:
PHP exec执行命令PHP
public function runLocalCommand($command) {
$command = trim($command);
$status = 1;
$log = '';
exec($command . ' 2>&1', $log, $status);
// 执行过的命令
$this->command = $command;
// 执行的状态
$this->status = !$status;
return $this->status;
}
去除了日志记录和其他的判断。
注意这里:
$this->status = !$status;
返回状态的时候取相反的值!
什么是opcode
也许你曾经尝试过用C/C++编写动态内容,虽然开发过程极其繁琐,但为了获得性能提升,这样做或许是值得的,它们可以将动态内容编译成二进制可执行文件,也就是目标代码,由操作系统进程直接装载运行。如今已经很少有人使用C/C++编写动态内容了,绝大多数的Web开发人员享受着当下的幸福时光,很多优秀的脚本语言可供选择,比如PHP,Ruby,Python,它们都属于解释型语言,所以用它们编写的动态内容都需要依赖响应的解释器程序来运行。
解释器程序也是一个二进制可执行文件,比如/bin/ruby,它同样可以直接在进程中运行,在运行过程中,解释器程序需要对输入的脚本代码进行分析,领会它们的旨意,然后执行它们。比如下面我们调用PHP的解释器,让它执行一段简单的脚本代码:
~ zfs$ php -r 'print 1+1;'
2
很好,它很快的输出了正确的结果,也许你觉的1+1的计算太小儿科,的确,在人类的大脑中计算1+1是很简单,几乎不用思考,但解释器的工作方式可不是你想象的那样,1+1和100+1000对它来说几乎没有什么区别,因为解释器核心引擎根本看不懂这些脚本代码,无法直接执行,所以需要进行一系列的代码分析工作,当解释器完成对脚本代码的分析后,便将它们生成可以直接运行的中间代码,也称为操作码(Operate Code,opcode)。
从程序代码到中间代码的这个过程,我们称为解释(parse),它由解释器来完成。如此相似的是,编译型语言中的编译器(如C语言的编译器gcc),也要将程序代码生成中间代码,这个过程我们称为编译(compile)。编译器和解释器的一个本质不同在于,解释器在生成中间代码后,便直接执行它,所以运行时的控制权在解释器;而编译器则将中间代码进一步优化,生成可以直接运行的目标程序,但不执行它,用户可以在随后的任意时间执行它,这时的控制权在目标程序,和编译器没有任何关系。
事实上,就解释和编译本身而言,它们的原理是相似的,都包括词法分析,语法分析,语义分析等,所以,有些时候将解释型语言中生成opcode的过程也称为"编译",需要你根据上下文来理解。
那么,opcode究竟是什么样的呢? 它又是如何解释生成的呢? 我们以PHP为例,来寻找这些答案。
PHP解释器的核心引擎为Zend Engine,可以很容易的查看它的版本:
~ zfs$ php -v
PHP 5.5.14 (cli) (built: Sep 9 2014 19:09:25)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
还记得前面我们曾经用PHP计算1+1的脚本代码吗? 我们来看看这段代码的opcode。在此之前,需要安装PHP的Parsekit扩展,它是一个用C编写的二进制扩展,由PECL来维护。有了Parsekit扩展后,我们就可以通过它提供的运行时API来查看任何PHP文件或者代码段的opcode。我们直接在命令行中调用parsekit_compile_string(),如下所示:
/usr/local/php/bin/php -r "var_dump(parsekit_compile_string('print 1+1;'));"
这样一来,我们便获得了这段代码的opcode,返回的是数组形式,结果如下所示:
array(20) {
["type"]=>
int(4)
["type_name"]=>
string(14) "ZEND_EVAL_CODE"
["fn_flags"]=>
int(0)
["num_args"]=>
int(0)
["required_num_args"]=>
int(0)
["pass_rest_by_reference"]=>
bool(false)
["uses_this"]=>
bool(false)
["line_start"]=>
int(0)
["line_end"]=>
int(0)
["return_reference"]=>
bool(false)
["refcount"]=>
int(1)
["last"]=>
int(5)
["size"]=>
int(5)
["T"]=>
int(2)
["last_brk_cont"]=>
int(0)
["current_brk_cont"]=>
int(4294967295)
["backpatch_count"]=>
int(0)
["done_pass_two"]=>
bool(true)
["filename"]=>
string(17) "Parsekit Compiler"
["opcodes"]=>
array(5) {
[0]=>
array(8) {
["address"]=>
int(33847532)
["opcode"]=>
int(1)
["opcode_name"]=>
string(8) "ZEND_ADD"
["flags"]=>
int(197378)
["result"]=>
array(3) {
["type"]=>
int(2)
["type_name"]=>
string(10) "IS_TMP_VAR"
["var"]=>
int(0)
}
["op1"]=>
array(3) {
["type"]=>
int(1)
["type_name"]=>
string(8) "IS_CONST"
["constant"]=>
&int(1)
}
["op2"]=>
array(3) {
["type"]=>
int(1)
["type_name"]=>
string(8) "IS_CONST"
["constant"]=>
&int(1)
}
["lineno"]=>
int(1)
}
[1]=>
array(7) {
["address"]=>
int(33847652)
["opcode"]=>
int(41)
["opcode_name"]=>
string(10) "ZEND_PRINT"
["flags"]=>
int(770)
["result"]=>
array(3) {
["type"]=>
int(2)
["type_name"]=>
string(10) "IS_TMP_VAR"
["var"]=>
int(1)
}
["op1"]=>
array(3) {
["type"]=>
int(2)
["type_name"]=>
string(10) "IS_TMP_VAR"
["var"]=>
int(0)
}
["lineno"]=>
int(1)
}
[2]=>
array(7) {
["address"]=>
int(33847772)
["opcode"]=>
int(70)
["opcode_name"]=>
string(9) "ZEND_FREE"
["flags"]=>
int(271104)
["op1"]=>
array(4) {
["type"]=>
int(2)
["type_name"]=>
string(10) "IS_TMP_VAR"
["var"]=>
int(1)
["EA.type"]=>
int(0)
}
["op2"]=>
array(3) {
["type"]=>
int(8)
["type_name"]=>
string(9) "IS_UNUSED"
["opline_num"]=>
string(1) "0"
}
["lineno"]=>
int(1)
}
[3]=>
array(7) {
["address"]=>
int(33847892)
["opcode"]=>
int(62)
["opcode_name"]=>
string(11) "ZEND_RETURN"
["flags"]=>
int(16777984)
["op1"]=>
array(3) {
["type"]=>
int(1)
["type_name"]=>
string(8) "IS_CONST"
["constant"]=>
&NULL
}
["extended_value"]=>
int(0)
["lineno"]=>
int(1)
}
[4]=>
array(5) {
["address"]=>
int(33848012)
["opcode"]=>
int(149)
["opcode_name"]=>
string(21) "ZEND_HANDLE_EXCEPTION"
["flags"]=>
int(0)
["lineno"]=>
int(1)
}
}
}
parsekit扩展的安装请参见这篇文章
系统缓存
它是指APC把PHP文件源码的编译结果缓存起来,然后在每次调用时先对比时间标记。如果未过期,则使用缓存的中间代码运行。默认缓存3600s(一小时)。但是这样仍会浪费大量CPU时间。因此可以在php.ini中设置system缓存为永不过期(apc.ttl=0)。不过如果这样设置,改运php代码后需要重启WEB服务器。目前使用较多的是指此类缓存。
用户数据缓存
缓存由用户在编写PHP代码时用apc_store和apc_fetch函数操作读取、写入的。如果数据量不大的话,可以一试。如果数据量大,使用类似memcache此类的更加专著的内存缓存方案会更好。
APC模块的安装
最简单的方法是直接使用pecl,在命令行下输入:/usr/local/php/bin/pecl install apc
然后按照提示一步步完成即可,示例如下:
[root@iZ23bm1tc0pZ ~]# /usr/local/php/bin/pecl install apc
downloading APC-3.1.13.tgz ...
Starting to download APC-3.1.13.tgz (171,591 bytes)
.....................................done: 171,591 bytes
55 source files, building
running: phpize
Configuring for:
PHP Api Version: 20100412
Zend Module Api No: 20100525
Zend Extension Api No: 220100525
Enable internal debugging in APC [no] : no
Enable per request file info about files used from the APC cache [no] : no
Enable spin locks (EXPERIMENTAL) [no] : no
Enable memory protection (EXPERIMENTAL) [no] : no
Enable pthread mutexes (default) [no] : no
Enable pthread read/write locks (EXPERIMENTAL) [yes] : yes
然后重启服务器即可:
lnmp nginx restart
先看一下没有使用apc情况下的压测结果:
[root@iZ23bm1tc0pZ ~]# ab -n1000 -c100 http://zfsphp.cn/index.php
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking zfsphp.cn (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: nginx
Server Hostname: zfsphp.cn
Server Port: 80
Document Path: /index.php
Document Length: 14341 bytes
Concurrency Level: 100
Time taken for tests: 15.517 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 14544000 bytes
HTML transferred: 14341000 bytes
Requests per second: 64.45 [#/sec] (mean)
Time per request: 1551.671 [ms] (mean)
Time per request: 15.517 [ms] (mean, across all concurrent requests)
Transfer rate: 915.34 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 2 4.8 0 17
Processing: 46 1481 277.0 1560 1638
Waiting: 42 1481 277.1 1560 1638
Total: 58 1482 272.8 1560 1638
Percentage of the requests served within a certain time (ms)
50% 1560
66% 1576
75% 1582
80% 1587
90% 1602
95% 1612
98% 1622
99% 1629
100% 1638 (longest request)
可见最大吞吐率只有64.45reqs/s
然后我们开启apc,测试结果如下:
[root@iZ23bm1tc0pZ ~]# ab -n1000 -c100 http://zfsphp.cn/index.php
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking zfsphp.cn (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: nginx
Server Hostname: zfsphp.cn
Server Port: 80
Document Path: /index.php
Document Length: 14341 bytes
Concurrency Level: 100
Time taken for tests: 7.122 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 14544000 bytes
HTML transferred: 14341000 bytes
Requests per second: 140.41 [#/sec] (mean)
Time per request: 712.189 [ms] (mean)
Time per request: 7.122 [ms] (mean, across all concurrent requests)
Transfer rate: 1994.29 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 2.4 0 10
Processing: 23 677 125.3 705 775
Waiting: 22 677 125.4 705 775
Total: 30 678 123.1 705 775
Percentage of the requests served within a certain time (ms)
50% 705
66% 719
75% 726
80% 730
90% 742
95% 750
98% 760
99% 765
100% 775 (longest request)
可见吞吐率提高了一倍多,达到140.41reqs/s。
然后,我们在开启动态内容缓存(楼主的博客用的是Smarty缓存),测试结果如下:
[root@iZ23bm1tc0pZ ~]# ab -n1000 -c100 http://zfsphp.cn/index.php
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking zfsphp.cn (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: nginx
Server Hostname: zfsphp.cn
Server Port: 80
Document Path: /index.php
Document Length: 14341 bytes
Concurrency Level: 100
Time taken for tests: 2.263 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 14544000 bytes
HTML transferred: 14341000 bytes
Requests per second: 441.98 [#/sec] (mean)
Time per request: 226.255 [ms] (mean)
Time per request: 2.263 [ms] (mean, across all concurrent requests)
Transfer rate: 6277.49 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 3.1 0 12
Processing: 18 215 38.1 222 255
Waiting: 18 215 38.3 222 255
Total: 26 216 35.6 223 255
Percentage of the requests served within a certain time (ms)
50% 223
66% 230
75% 232
80% 234
90% 237
95% 239
98% 240
99% 243
100% 255 (longest request)
这一次吞吐率居然达到441.98reqs/s,提高了三倍多,相比最初的64.45reqs/s提高了近7倍,可见使用apc的opcode缓存配合Smarty缓存,对网站性能的优化效果还是相当明显的。
演示代码
运行效果(图1)
运行效果(图2)
主要封装函数
multi_process();
根据参数,创建指点数目的子进程。
亮点功能1:子进程各种异常退出,比如segment fault, Allowed memory size exhausted等,中断一个子进程后,父进程会重新fork一个新进程顶上去,保持子进程数量。如果子进程里完成任务(比如判断tid达到10000),可以在子进程里exit(9),父进程会收到这个退出状态(9),然后等待所有子进程退出,最后退出自身进程。
亮点功能2:与curl封装函数一起实现了一统计功能,在程序关闭后会显示出一些主要的统计信息(图2的底部)。
mp_counter();
在父进程以及所有子进程之间通信,负责协调分配各子进程的任务,使用了锁机制。可以设置’init’参数重置计数,可以设置每次更新计数的值。
curl_get();
对curl相关函数的封装,加入了大量的错误机制,支持POST,GET,Cookie,Proxy,下载。
mp_msg();
实现规范之一就是,每条任务处理完,只输出一行信息。
亮点功能:这个函数会判断终端的高度和宽度,实现每一屏内容会显示一条统计信息(图1的紫色行),便于观察程序的执行情况,控制每一行输出的长度,保持一条信息不会超过一行。
rand_exit();
众所周知,PHP存在内在泄露的问题,所以每一个子进程里执行一定次数的任务后就退出,由multi_process()负责自动建立新的子进程(如图1中的绿色行)。
程序效率
本次测试使用的是Vultr的最低配置机器,1 CPU(3.6GHz),768MB RAM,美国LA机房(一定程度上影响了抓取速度)。
执行了十多分钟后,统计信息如下:
运行期间内存占用统计(while true; do psmem | grep php;sleep 10; done)如下:
vmstat 1命令结果如下
iftop带宽监控如下:
50个子进程,执行11分55秒,抓取50951次,按这个速度计算,一天可以抓取615万次。
所有进程(1父进程+50子进程)共占用内存约60MB,占用CPU约20%(1核心),带宽占用约7-8Mbps。
不同进程数量的抓取速度对比:
1个进程
100个进程
多进程的封装几乎完美,但curl由于它的功能太过于丰富和强大,可能永远也无法达到完美
代码如下
curl.lib.php
代码如下 | 复制代码 |
<?php // 命令行颜色输出 /* /* /* /* // cookie和临时文件目录 // 清除过期的cookie文件和下载临时文件 /** /** /** if(!$header_text){ // 处理状态码 /** return curl_func($url, $method, $data, $path, $proxy); /**
/** function img_down($url, $path_pre){ function get_img_ext($path){ /** } /** /** /** /** // 控制台输出颜色 // 去除URL中的/../ // 去除实体转码 // 统计数据 for($i = 0; $i < curl_config_get('retry'); $i++){ // 初始化 // 设置超时 // 接收网页内容到变量 // 忽略SSL验证 // 设置referer, 在文件里配置的优先级最高 // 设置HTTP请求标识,在文件里配置的优先级最高 curl_setopt($ch, CURLOPT_USERAGENT, $useragent); // 出口IP // 设置代理 // 设置允许接收gzip压缩数据,以及解压,抓取HEADER时不使用(获取不到正确的文件大小,影响判断下载成功) // 遇到301和302转向自动跳转继续抓取,如果用于WEB程序并且设置了open_basedir,这个选项无效 // 启用cookie // 设置post参数内容 // 设置用于下载的参数 // 仅获取header // 抓取结果 // 调试curl时间,记录连接时间,等待时间,传输时间,总时间。 // 关闭CURL句柄 // 如果CURL有错误信息则判断为抓取失败,重试 // 统计流量 // 对结果进行处理 if(in_array($status_code, array_merge(range(400, 417), array(500, 444)))){ if(empty($savepath)){ // 分析页面编码 // 转码条件:1)匹配到编码, 2)返回编码不为空, 3)匹配到的编码和返回编码不相同 // iconv如果失败则返回空白页 // 统计下载文件量 return TRUE; // 如果是下载或者抓取header,并且错误代码为6(域名无法解析),则不输出错误。失效的图片引用太多了。 // 统计数据 return FALSE; /** // 多并发下建议关闭黄色错误输出 if(php_sapi_name() != 'cli'){ if(!in_array($color, $available_msg)){ echo "{$reverse}".$colors[$color]."({$method})[cURL ERROR: {$msg}] {$url}{$end}\n"; /** /** function relative_to_absolute($content, $url) { preg_match("/(http|https|ftp):\/\/[^\/]*/", $url, $preg_base); preg_match("/(http|https|ftp):\/\/.*\//", $url, $preg_full); return $content; /** $cookie_files = glob("{$cookie_dir}curl_*_pid_*"); foreach($files as $file){
}
function curl_rand_ua_pc(){ function curl_rand_ua_mobile(){ function curl_config_get($key){ if(!empty($curl_config[getmypid()][$key])){ function curl_config_set($key, $val){ function curl_set_ua($ua){ function curl_set_referer($referer){ function curl_set_retry($retry){ function curl_set_conntimeout($conntimeout){ function curl_set_fetchtimeout($fetchtimeout){ function curl_set_downtimeout($downtimeout){ |
process.lib.php
代码如下 | 复制代码 |
<?php declare(ticks = 1); // 中断信号 // 命令行颜色输出 // 程序开始运行时间 // 父进程PID // 文件保存目录,/dev/shm/是内存空间映射到硬盘上,IO速度快。 // 清理过期资源(文件和SEM信号锁),每次程序执行都需要调用,清除掉之前执行时的残留文件。 // 判断是否在子进程中 /** // 父进程PID或者自身PID // 系统启动时间 // 进程启动时间 // 由父进程ID确定变量文件路径前缀 // 由于系统启动时间和当前父进程启动时间(jiffies格式)确定计数使用的文件 // 更新计数,先锁定 if(!file_exists($cur_path)){ $counter = 0; // 更新记数, 继续研究下判断init不能用== // 写入计数,解锁 return $new_counter; /** if(empty($num)){ // 记录进程数量,统计用 // 子进程数量 // 任务完成标识 while(TRUE) { // 清空子进程退出状态 // 如果任务未完成,并且子进程数量没有达到最高,则创建 // 注册父进程的信号处理函数 //$stat && pcntl_signal(SIGINT, "signal_handler"); echo "{$reverse}{$green}[+]New Process Forked: {$pid}{$end}\n"; // 1,注册一个信号,处理函数直接exit(),目的是让子进程不进行任何处理,仅由主进程处理这个信号 // 注册信号后直接返回,继续处理主程序的后续部分。 // 子进程管理部分 // 统计信息 // 子进程退出状态码为9时,则判断为所有任务完成,然后等待所有子进程退出
if(strpos($script, '/') === FALSE || strpos($script, '..') !== FALSE){ return $path; function final_stat(){ // 时间统计 // curl抓取统计 $down_total = mp_counter('down_total', 0); $header_total = mp_counter('header_total', 0); $download_size = hs(mp_counter('download_size', 0)); echo " Request Stat: Fetch({$fetch_success}/{$fetch_total}), Header({$header_success}/{$header_total}), "; // curl流量统计 // 效率统计 echo "========================================================================{$end}\n"; /** function sub_process_exit(){ function hnum($num){ /**
/** if(!function_exists('get_ppid')){ // 以进程(多进程运行时,使用父进程)为单位,每个进程使用一个锁。 // 解除锁 // 清理资源(文件和SEM信号锁) // 清除sem的文件和信号量 // 清除mp_counter的文件(仅此类型文件不可重用,所以严格处理,匹配系统启动时间和进程启动时间) // 清除文件 // 系统启动时间 // 如果是在子进程中调用,则取父进程的启动时间。如果不是在子进程中调用,则取自身启动时间。时间都是jiffies格式。 // 防止PHP进程内存泄露,每个子进程执行完一定数量的任务就退出。 // 单次的任务结果输出函数 // 整理统计信息 // cron方式运行 $lock = sem_lock('mp_msg'); $t_cols = mp_counter('t_cols', 0); if($t_lines <= 1){ $process_num = mp_counter('process_num', 0); $fetch_total = mp_counter('fetch_total', 0); echo "{$reverse}{$purple}"; } |
相关文章
- 下面本文章来给大家介绍在php中成员变量的一些对比了,文章举了四个例子在这例子中分别对不同成员变量进行测试与获取操作,下面一起来看看。 有如下4个代码示例,你认...2016-11-25
- php 获取用户IP与IE信息程序 function onlineip() { global $_SERVER; if(getenv('HTTP_CLIENT_IP')) { $onlineip = getenv('HTTP_CLIENT_IP');...2016-11-25
- php获取一个文件夹的mtime的程序了,这个就是时间问题了,对于这个问题我们来看小编整理的几个例子,具体的操作例子如下所示。 php很容易获取到一个文件夹的mtime,可以...2016-11-25
- 获取网站icon,常用最简单的方法就是通过website/favicon.ico来获取,不过由于很多网站都是在页面里面设置favicon,所以此方法很多情况都不可用。 更好的办法是通过google提供的服务来实现:http://www.google.com/s2/favi...2014-06-07
- 主要功能:获取浏览器显示区域(可视区域)的高度 : $(window).height(); 获取浏览器显示区域(可视区域)的宽度 :$(window).width(); 获取页面的文档高度 $(document).height(); 获取页面的文档宽度 :$(document).width();...2015-10-21
- jquery中jquery.offset().top / left用于获取div距离窗口的距离,jquery.position().top / left 用于获取距离父级div的距离(必须是绝对定位的div)。 (1)先介绍jquery.offset().top / left css: 复制代码 代码如下: *{ mar...2013-10-13
- 1、先讲讲JQuery的概念,JQuery首先是由一个 America 的叫什么 John Resig的人创建的,后来又很多的JS高手也加入了这个团队。其实 JQuery是一个JavaScript的类库,这个类库集合了很多功能方法,利用类库你可以用简单的一些代...2014-05-31
- 这篇文章主要为大家详细介绍了python实现学生通讯录管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-25
- 这篇文章主要为大家详细解析了BootStrap栅格系统、表单样式与按钮样式源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2017-01-23
- 这篇文章主要介绍了C#获取字符串后几位数的方法,实例分析了C#操作字符串的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 如果是为了取到tagName后再进行判断,那直接用下面的代码会更方便: $(element).is('input') 如果是要取到标签用作到别的地方,可以使用一下代码: $(element)[0].tagName 或: $(element).get(0).tagName...2014-05-31
- 复制代码 代码如下:$nodes = @$xpath->query("//*[@id='main_pr']/img/@src");$prurl = $nodes->item(0)->nodeValue;...2013-10-04
- 本文为代码分享,也是在工作中看到一些“大牛”的代码,做做分享。 具体是这样的,如下一个二维数组,是从库中读取出来的。 代码清单: 复制代码 代码如下: $user = array( 0 => array( 'id' => 1, 'name' => '张三', 'ema...2014-06-07
- 现实中我们经常看到这样的说明,排名不分先后,按姓名首字母进行排序。这是中国人大多数使用的排序方法。那么在php程序中该如何操作呢?下面就分享一下在php程序中获取汉字拼音的首字母的方法,在网上搜到的大多数是有问题的...2015-10-23
- 如今高要求的分布式系统的建造者遇到了不能完全由传统的面向对象编程(OOP)模型解决的挑战,但这可以从Actor模型中获益。...2021-05-20
- 本篇文章是对使用C#获取系统特殊文件夹路径的解决方法进行了详细的分析介绍,需要的朋友参考下...2020-06-25
- 网上也有很多类似的方法,不过都存在这样那样的不严谨的问题,本文就不一一分析了,这里只给出最正确的利用php 获取文件扩展名(文件后缀名)的方法。 function get_extension($filename){ return pathinfo($filename,PATHIN...2015-10-30
- 护卫神·主机管理系统该版本支持在Windows Server 200320082012,含32位和64位,直接开设配置WEB站、FTP站,以及SQL Server和MySQL,是您开设和管理虚拟主机的绝好帮手。但是对于新用户可能在使用上有一些困难,因此请仔细阅读如下说明文档...2016-01-27
- 这篇文章主要介绍了基于JavaScript获取鼠标位置的各种方法 ,需要的朋友可以参考下...2015-12-18
- 这篇文章主要介绍了C#获取变更过的DataTable记录的实现方法,对初学者很有学习借鉴价值,需要的朋友可以参考下...2020-06-25