PHP implements multi-process, multi-threading

Notes for newbies:

Orphaned process: A parent process exits while one or more of its child processes are still running, then those child processes will become orphaned. The orphan process will be adopted by the init process (process number is 1), and the init process will complete the state collection work for them.

  Zombie process: A process uses fork to create a child process. If the child process exits and the parent process does not call wait or waitpid to obtain the status information of the child process, the process descriptor of the child process is still stored in the system. Such a process is called a zombie process.

  Zombie process harm: If the process does not call wait / waitpid,  the reserved information will not be released, and its process ID will always be occupied, but the process ID that the system can use is limited, if a large number of zombies are generated process, the system will not be able to generate new processes because there is no available process number. This is the harm of zombie processes and should be avoided. Any child process (except init) does not disappear immediately after exit(), but leaves a data structure called a zombie process (Zombie) waiting for the parent process to process it.

  The zombie process that has been generated, the solution: kill the parent process, the zombie process it generates becomes an orphan process, these orphan processes will be taken over by the init process, the init process will wait() these orphan processes and release the system they occupy resources in the process table.

  Zombie process solution

  (1) Through the signal mechanism

    When the child process exits, the SIGCHILD signal is sent to the parent process, and the parent process handles the SIGCHILD signal. Call wait in the signal handler to handle the zombie process.

  (2) fork twice

    Section 8.6 of "Advanced Programming in the Unix Environment" is very detailed. The principle is to turn the child process into an orphan process, so that its parent process becomes the init process, and the zombie process can be processed through the init process.

Multiprocessing vs Multithreading

Contrast dimension

multi-Progress

Multithreading

Summarize

Data sharing and synchronization

Data sharing is complex and requires IPC; data is separated and synchronization is simple

Because of the shared process data, data sharing is simple, but it is also because of this reason that synchronization is complex

Each has its own advantages

memory, CPU

Occupies a lot of memory, switching is complicated, and CPU utilization is low

Low memory usage, easy switching, and high CPU utilization

thread dominance

Create, destroy, switch

Creating and destroying, switching is complicated, and the speed is slow

Creating and destroying, switching is simple and fast

thread dominance

programming, debugging

Simple programming and easy debugging

Complex programming, complex debugging

process dominance

reliability

Processes do not affect each other

If a thread hangs, it will cause the whole process to hang

process dominance

distributed

It is suitable for multi-core and multi-machine distribution; if one machine is not enough, it is relatively simple to expand to multiple machines

Suitable for multi-core distributed

process dominance

 

1) Priority threads that need to be frequently created and destroyed

See the comparison above for the reasons.

The most common application of this principle is a web server. A connection is established to establish a thread, and the thread is destroyed when it is disconnected. If a process is used, the cost of creation and destruction is unbearable.

2) Preferential use of threads that require a lot of computation

The so-called large-scale calculation, of course, consumes a lot of CPU, and the switching is frequent. In this case, the thread is the most suitable.

The most common principles of this kind are image processing and algorithm processing.

3) Strongly related processing threads, weakly related processing processes

What is strong correlation and weak correlation? It is difficult to define in theory, but a simple example will make it clear.

The general server needs to complete the following tasks: message sending and receiving, message processing. "Message sending and receiving" and "message processing" are weakly related tasks, and "message processing" may be further divided into "message decoding" and "business processing". These two tasks are relatively more closely related. Therefore, "message sending and receiving" and "message processing" can be designed by process, and "message decoding" and "service processing" can be designed by thread.

Of course, this division method is not static and can also be adjusted according to the actual situation.

4) It may be extended to multi-machine distributed processes and multi-core distributed threads

See the comparison above for the reasons.

5) When all the needs are met, use the method you are most familiar with and best at

As for the so-called "complexity and simplicity" of the dimensions of "data sharing, synchronization", "programming, debugging" and "reliability", I can only say: there is no clear choice. But I can tell you a selection principle: if both multiprocessing and multithreading can meet the requirements, then choose the one you are most familiar with and good at. 

It should be reminded that although I have given so many selection principles, the practical application is basically a combination of "process + thread". Don't really fall into an either-or misunderstanding.

 

Consume resources:

从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。线程是进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。

线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。

通讯方式:

进程之间传递数据只能是通过通讯的方式,即费时又不方便。线程时间数据大部分共享(线程函数内部不共享),快捷方便。但是数据同步需要锁对于static变量尤其注意

线程自身优势:

提高应用程序响应;使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上;

改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

1. [代码]PHP实现多进程并行操作(可做守护进程) 

/**
 * Entry function
 * Save this file as ProcessOpera.php
 * Run /usr/local/php/bin/php ProcessOpera.php in terminal & 
 * View process ps aux|grep php
 */
 
 
ProcessOpera("runCode", array(), 8);
 
/**
 * run Code
 */
function runCode($opt = array()) {
   //code that needs to be run in the daemon process
}
 
/**
 * $func executes specific things for the child process function name
 * $opt is the parameter array form of $func
 * $pNum is the number of child processes fork
 */
function ProcessOpera($func, $opts = array(), $pNum = 1) {
    while(true) {
        $pid = pcntl_fork();
        if($pid == -1) {
            exit("pid fork error");
        }   
        if($pid) {
            static $execute = 0;
            $execute++;
            if($execute >= $pNum) {
                pcntl_wait($status);
                $execute--;
            }   
        } else {
            while(true) {
                //somecode
                $func($opts);
                sleep(1);
            }   
            exit(0);
        }   
    }   

}

2. [Code] PHP implements multi-threaded operation 

class My extends Thread {
    protected $name;
    public $runing;
    function __construct($name){
        $this->runing=1;
        $this->param=0;
        $this->name=$name;
    }
    public function run() {
        while($this->runing){
            if($this->param){
                $time=rand(1,5);
                echo 'I am thread '.$this->name.',pid: '.$this->getCreatorId().",param: {$this->param},need {$time}s\n"; 
                sleep($time);
                $this->param=0;
            }else{
                echo "Thread {$this->name} waiting...\n";
            }
            sleep(1);
        }
    }
}
$pool=array();
$pool[]=new My('a');
$pool[]=new My('b');
$pool[]=new My('c');
//开启所有线程
foreach ($pool as $w) {
    $w->start();
}
//派发任务
unset($w);
for($i=1;$i<10;$i++){
    $woker_content=$i;
    while(1){
        foreach($pool as $w){
            if(!$w->param){
                $w->param=$woker_content;
                echo "Thread {$w->name} empty,put param {$woker_content}.\n";
                break 2;
            }
        }
        sleep(1);    
    }
}


unset($w);
while(count($pool)){
    foreach ($pool as $k => $w) {
        if(!$w->param){
            $w->runing=false;
            unset($pool[$k]);
            echo "Thread {$w->name} end,exit!\n";
        }
    }
    sleep(1);
}


echo 'All thread end!';


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325524365&siteId=291194637