Purpose of this article
In this paper, we explain the Linux environment using PHP for concurrent task processing and how to use pipe to synchronize data between processes. It's easy to write, as a memo.
PHP Multi-process
Use the multi-process functionality with the PCNTL_XXX series functions. Note: Pcntl_xxx can only run in the PHP CLI (command line) environment, in the Web server environment, there will be unexpected results, please use it with caution!
Piping pipe
Pipelines are used to host communication data between abbreviations. To facilitate understanding, the pipeline can be likened to a file, process a writes the data to the pipe p, and then process B reads the data from the pipe p. PHP provides the same pipeline operations API as the API for manipulating files, except that the POSIX_MKFIFO function is used to create pipelines, and reads and writes are the same as file manipulation functions. Of course, you can use the file to simulate the pipeline directly, but you can't use the features of the pipeline.
Zombie Process
At the end of the child process, the parent process does not wait for it (by calling wait or Waitpid), and the child process does not release all resources after the end (wasted!). ), this process is called the zombie process, he stored the child process at the end of the relevant data, if the zombie process too much, will occupy a lot of system resources (such as memory), affecting the performance of the machine.
Code
Nonsense less say directly on the code
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 6667686970717273747576777879808182838485 |
/**
* this is a demo for php fork and pipe usage. fork use
* to create child process and pipe is used to sychoroize
* the child process and its main process.
* @author bourneli
* @date: 2012-7-6
*/
define(
"PC"
, 10);
// 进程个数
define(
"TO"
, 4);
// 超时
define(
"TS"
, 4);
// 事件跨度,用于模拟任务延时
if
(!function_exists(
‘pcntl_fork‘
)) {
die
(
"pcntl_fork not existing"
);
}
// 创建管道
$sPipePath
=
"my_pipe."
.posix_getpid();
if
(!posix_mkfifo(
$sPipePath
, 0666)) {
die
(
"create pipe {$sPipePath} error"
);
} // 模拟任务并发
for
(
$i
= 0;
$i
< PC; ++
$i
) {
$nPID
= pcntl_fork();
// 创建子进程
if
(
$nPID
== 0) {
// 子进程过程
sleep(rand(1,TS));
// 模拟延时
$oW
=
fopen
(
$sPipePath
,
‘w‘
);
fwrite(
$oW
,
$i
.
"\n"
);
// 当前任务处理完比,在管道中写入数据
fclose(
$oW
);
exit
(0);
// 执行完后退出
}
}
// 父进程
$oR
=
fopen
(
$sPipePath
,
‘r‘
);
stream_set_blocking(
$oR
, FALSE);
// 将管道设置为非堵塞,用于适应超时机制
$sData =
‘‘
;
// 存放管道中的数据
$nLine
= 0;
$nStart
= time();
while
(
$nLine
< PC && (time() -
$nStart
) < TO) {
$sLine =
fread
(
$oR
, 1024);
if
(
empty
(
$sLine
)) {
continue
;
}
echo
"current line: {$sLine}\n"
;
// 用于分析多少任务处理完毕,通过‘\n’标识
foreach
(
str_split
(
$sLine
)
as
$c
) {
if
(
"\n"
==
$c
) {
++
$nLine
;
}
}
$sData
.=
$sLine
;
}
echo
"Final line count:$nLine\n"
;
fclose(
$oR
);
unlink(
$sPipePath
);
// 删除管道,已经没有作用了
// 等待子进程执行完毕,避免僵尸进程
$n
= 0;
while
(
$n
< PC) {
$nStatus
= -1;
$nPID
= pcntl_wait(
$nStatus
, WNOHANG);
if (
$nPID
> 0) {
echo
"{$nPID} exit\n"
;
++
$n
;
}
}
// 验证结果,主要查看结果中是否每个任务都完成了
$arr2 =
array
();
foreach
(
explode
(
"\n"
,
$sData
)
as
$i
) {
// trim all
if
(
is_numeric
(trim(
$i
))) {
array_push
(
$arr2
,
$i
);
}
}
$arr2
=
array_unique
(
$arr2
);
if
(
count
(
$arr2
) == PC) {
echo
‘ok‘
;
}
else
{
echo "error count "
.
count
(
$arr2
) .
"\n"
;
var_dump(
$arr2
);
}
|
OK, finished, note write the comparison clear, the execution result is as follows:
PHP multi-process processing parallel Processing Task instance