Home  >  Article  >  Backend Development  >  A preliminary introduction to PHP multi-process programming

A preliminary introduction to PHP multi-process programming

不言
不言Original
2018-07-05 10:37:061210browse

This article mainly introduces the initial introduction to PHP multi-process programming. It has a certain reference value. Now I share it with everyone. Friends in need can refer to it.

Envy Naruto in Naruto Shadow clone? Yes, PHP programs can activate shadow clones! If you want to complete a task but feel that one process is too slow, then try using multiple processes. This article will introduce the basic needs of PHP multi-process, how to create multi-process and basic signal control. It will not tell you how to communicate and share information between processes for the time being.

1. Preparation

Before you start, please make sure you are not using the M$ Windows platform (because I don’t have Windows). Linux/BSD/Unix should be no problem. After confirming the working environment, let's see if the PHP modules we need are available. Open the terminal and enter the following command:

$ php -m

This command checks and prints all the currently enabled extensions of PHP. Check whether pcntl and posix are in the output list.

1.1. pcntl

If pcntl cannot be found, it is likely that this extension was not compiled during compilation. If you compiled and installed PHP like me, you need to recompile and install PHP. Remember to add the --enable-pcntl parameter when configuring.

$ cd /path/to/php_source_code_dir 
$ ./configure [some other options] --enable-pcntl
$ make && make install

1.2. posix

This product will usually be installed by default, as long as you do not add --disable-posix when compiling.

2. Preliminary knowledge

Before continuing, you also need to have a little understanding of Linux multi-process. What's going on with multi-processing? This is slightly different from the shadow clone in Naruto. First of all, Naruto grew up from a young age, like 16 years old, cough. One day he activated his shadow clone and split into five of himself. Obviously, these clones are also 16-year-old Naruto and not babies who cry when they are born and don't understand anything (that's called cloning). Then, here comes the difference: the clones have become independent people doing their own things, and they no longer know what other clones and the original body have done (of course they will not accumulate experience like in the cartoon) To the original person). Unless they communicate with each other, only things before the age of 16 are their common memories.

Some classmates said, boss, aren’t you cheating on me? I haven't watched Naruto! Then you should take a look...

Finally, the preparatory knowledge is over, just have a general understanding of what the child processes created by the main process are like. The code of the child process is exactly the same as the main process, and the other part of the same thing is everything executed until the shadow clone is launched. For details, please refer to the "Operating System" course.

3. The Art of Shadow Clone

So, how can you understand the contents of the scroll without some basic knowledge? When I opened the scroll, I first saw a word: fork.

3.1. fork

Fork? The forks are bifurcated, one becomes multiple! That’s pretty much what it means. Use this command to create a child process. You need to use the pcntl_fork() function here. (You can first take a brief look at the introduction of this function in the PHP manual.) Create a PHP script:

$pid = pcntl_fork(); // 一旦调用成功,事情就变得有些不同了
if ($pid == -1) {    
die('fork failed');
} else if ($pid == 0) {} else {}

pcntl_fork()The function creates a child process. The only difference between the child process and the parent process The PID (process ID) and PPID (parent process ID) are different. To view the process in the terminal, use the ps command (ask man how to use ps: man ps). When the function returns -1, it means that the fork failed. Try adding a sentence in front of if: echo $pid . PHP_EOL;. Run your script, the output may be like the following (the result shows that the code of the child process and the parent process are the same):

67789 # 这个是父进程打印的
0     # 这个是子进程打印的

pcntl_fork()After the function call is successful, in the parent process The PID of the child process will be returned, and 0 is returned in the child process. Therefore, the if branch is used directly below to control the parent process and the child process to do different things.

3.2. Assign tasks

Then let’s talk about Naruto’s shadow clone when he was 16 years old, and assign two simple output tasks to the original body and clone: ​​

$parentPid = getmypid(); // 这就是传说中16岁之前的记忆
$pid = pcntl_fork(); // 一旦调用成功,事情就变得有些不同了
if ($pid == -1) {    
die('fork failed');
} else if ($pid == 0) {    
$mypid = getmypid(); // 用getmypid()函数获取当前进程的PID    
echo 'I am child process. My PID is ' . $mypid . ' and my father's PID is ' . $parentPid . PHP_EOL;
} else {    
echo 'Oh my god! I am a father now! My child's PID is ' . $pid . ' and mine is ' . $parentPid . PHP_EOL;}

The output result may be like this:

Oh my god! I am a father now! My child's PID is 68066 and mine is 68065
I am child process. My PID is 68066 and my father's PID is 68065

Let me emphasize again, pcntl_fork()After the call is successful, one program becomes two programs: one program gets the The value of the $pid variable is 0, which is the child process; the value of $pid obtained by another program is greater than 0. This value is the PID of the child process, which is the parent process. In the branch statement below, different codes are run due to different $pid values. Let me emphasize again: the code of the child process is the same as that of the parent process. Therefore, different tasks must be assigned to them through branch statements.

3.3. 子进程回收

刚刚有man ps么?一般我习惯用ps aux加上grep命令来查找运行着的后台进程。其中有一列STAT,标识了每个进程的运行状态。这里,我们关注状态Z:僵尸(Zombie)。当子进程比父进程先退出,而父进程没对其做任何处理的时候,子进程将会变成僵尸进程。Oops,又跟火影里的影分身不一样了。鸣人的影分身被干死了以后就自动消失了,但是这里的子进程分身死了话还留着一个空壳在,直到父进程回收它。僵尸进程虽然不占什么内存,但是很碍眼,院子里一堆躺着的僵尸怎么都觉得怪怪的。(别忘了它们还占用着PID)

一般来说,在父进程结束之前回收挂掉的子进程就可以了。在pcntl扩展里面有一个pcntl_wait()函数,它会将父进程挂起,直到有一个子进程退出为止。如果有一个子进程变成了僵尸的话,它会立即返回。所有的子进程都要回收,所以多等等也没关系啦!

3.4. 父进程先挂了

如果父进程先挂了怎么办?会发生什么?什么也不会发生,子进程依旧还在运行。但是这个时候,子进程会被交给1号进程,1号进程成为了这些子进程的继父。1号进程会很好地处理这些进程的资源,当它们结束时1号进程会自动回收资源。所以,另一种处理僵尸进程的临时办法是关闭它们的父进程。

4. 信号

一般多进程的事儿讲到上面就完了,可是信号在系统中确实是一个非常重要的东西。信号就是信号灯,点亮一个信号灯,程序就会做出反应。这个你一定用过,比如说在终端下运行某个程序,等了半天也没什么反应,可能你会按 Ctrl+C 来关闭这个程序。实际上,这里就是通过键盘向程序发送了一个中断的信号:SIGINT。有时候进程失去响应了还会执行kill [PID]命令,未加任何其他参数的话,程序会接收到一个SIGTERM信号。程序收到上面两个信号的时候,默认都会结束执行,那么是否有可能改变这种默认行为呢?必须能啊!

4.1. 注册信号

人是活的程序也是活的,只不过程序需要遵循人制定的规则来运行。现在开始给信号重新设定规则,这里用到的函数是pcntl_signal()(继续之前为啥不先查查PHP手册呢?)。下面这段程序将给SIGINT重新定义行为,注意看好:

// 定义一个处理器,接收到SIGINT信号后只输出一行信息
function signalHandler($signal) {    
if ($signal == SIGINT) {        
echo 'signal received' . PHP_EOL;    }}
// 信号注册:当接收到SIGINT信号时,调用signalHandler()函数pcntl_signal(SIGINT, 'signalHandler');while (true) {    sleep(1);    // do something    pcntl_signal_dispatch(); // 接收到信号时,调用注册的signalHandler()}

执行一下,随时按下 Ctrl+C 看看会发生什么事。

4.2. 信号分发

说明一下:pcntl_signal()函数仅仅是注册信号和它的处理方法,真正接收到信号并调用其处理方法的是pcntl_signal_dispatch()函数。试试把// do something替换成下面这段代码:

for ($i = 0; $i < 1000000; $i++) {    
echo $i . PHP_EOL;    
usleep(100000);}

在终端下执行这个脚本,当它不停输出数字的时候尝试按下 Ctrl+C 。看看程序有什么响应?嗯……什么都没有,除了屏幕可能多了个^C以外,程序一直在不停地输出数字。因为程序一直没有执行到pcntl_signal_dispatch(),所以就并没有调用signalHandler(),所以就没有输出signal received

4.3. 版本问题

如果认真看了PHP文档,会发现pcntl_signal_dispatch()这个函数是PHP 5.3以上才支持的,如果你的PHP版本大于5.3,建议使用这个方法调用信号处理器。5.3以下的版本需要在注册信号之前加一句:declare(ticks = 1);表示每执行一条低级指令,就检查一次信号,如果检测到注册的信号,就调用其信号处理器。想想就挺不爽的,干嘛一直都检查?还是在我们指定的地方检查一下就好。

4.4. 感受僵尸进程

现在我们回到子进程回收的问题上(差点忘了= =")。当你的一个子进程挂了(或者说是结束了),但是父进程还在运行中并且可能很长一段时间不会退出。一个僵尸进程从此站起来了!这时,保护伞公司(内核)发现它的地盘里出现了一个僵尸,这个僵尸是谁儿子呢?看一下PPID就知道了。然后,内核给PPID这个进程(也就是僵尸进程的父进程)发送一个信号:SIGCHLD。然后,你知道怎么在父进程中回收这个子进程了么?提示一下,用pcntl_wait()函数。

4.5. Send signal

I hope you have carefully manned the kill command just now. It actually sends a signal to the process. In PHP, you can also call the posix_kill() function to achieve the same effect. With it, you can control the running of other child processes in the parent process. For example, to close all child processes before the parent process ends, then record the PIDs of all child processes in the parent process when fork, and send end signals to the child processes in sequence before the parent process ends.

5. Practice

PHP's multi-process is quite similar to C. Once you understand it, it will be similar if you write it in other languages. If you have time, try writing a small program and experience it personally:

  1. 16-year-old Naruto sent shadow clones and split into 5 clones

  2. Each clone survives randomly for 10 to 30 seconds, and outputs something every second.

  3. Ensure that the original clone can feel the end of the clone, and then activate another clone. Ensure that there are at most 5 clones

  4. Do not usenohup, so that the original body can still run after the terminal is closed

  5. Write the number of clones (5) into a configuration file. When sending a signal to the original body (consider using SIGUSR1 or SIGUSR2), the original body reads the configuration file and updates the maximum number of clones allowed

  6. If there are too many clones, close a few; if there are fewer, split out a few more

Tips:

  1. Use whileLoop to ensure that the process is running, pay attention to sleep to avoid 100% CPU usage

  2. When the terminal running the process is closed, the program will receive a SIGHUP signal

  3. You can use the parse_ini_file() function to parse the INI configuration file

The above is the entire content of this article, I hope It will be helpful for everyone’s learning. For more related content, please pay attention to the PHP Chinese website!

Related recommendations:

Understanding of PHP polymorphism

Introduction to PHP file programming

The above is the detailed content of A preliminary introduction to PHP multi-process programming. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn