PHP多进程实践
PHP多进程实践
1. 直接方式
pcntl_fork() 创建一个进程,在父进程返回值是子进程的pid,在子进程返回值是0,-1表示创建进程失败。跟C非常相似。
测试脚本 test.php
// example of multiple processes date_default_timezone_set( 'Asia/Chongqing'); echo "parent start, pid ", getmypid(), "\n" ; beep(); for ($i=0; $i<3; ++$i){ $pid = pcntl_fork(); if ($pid == -1){ die ("cannot fork" ); } else if ($pid > 0){ echo "parent continue \n"; for ($k=0; $k<2; ++$k){ beep(); } } else if ($pid == 0){ echo "child start, pid ", getmypid(), "\n" ; for ($j=0; $j<5; ++$j){ beep(); } exit ; } } // *** function beep(){ echo getmypid(), "\t" , date( 'Y-m-d H:i:s', time()), "\n" ; sleep(1); }
用命令行运行
#php -f test.php
输出结果
parent start, pid 1793
1793 2013-01-14 15:04:17
parent continue
1793 2013-01-14 15:04:18
child start, pid 1794
1794 2013-01-14 15:04:18
1794 2013-01-14 15:04:19
1793 2013-01-14 15:04:19
1794 2013-01-14 15:04:20
parent continue
1793 2013-01-14 15:04:20
child start, pid 1795
1795 2013-01-14 15:04:20
17931794 2013-01-14 15:04:212013-01-14 15:04:21
1795 2013-01-14 15:04:21
1794 2013-01-14 15:04:22
1795 2013-01-14 15:04:22
parent continue
1793 2013-01-14 15:04:22
child start, pid 1796
1796 2013-01-14 15:04:22
1793 2013-01-14 15:04:23
1796 2013-01-14 15:04:23
1795 2013-01-14 15:04:23
1795 2013-01-14 15:04:24
1796 2013-01-14 15:04:24
1796 2013-01-14 15:04:25
1796 2013-01-14 15:04:26
从中看到,创建了3个子进程,和父进程一起并行运行。其中有一行格式跟其他有些不同,
17931794 2013-01-14 15:04:212013-01-14 15:04:21
因为两个进程同时进行写操作,造成了冲突。
2. 阻塞方式
用直接方式,父进程创建了子进程后,并没有等待子进程结束,而是继续运行。似乎这里看不到有什么问题。如果php脚本并不是运行完后自动结束,而是常驻内存的,就会造成子进程无法回收的问题。也就是僵尸进程。可以通过pcntl_wai()方法等待进程结束,然后回收已经结束的进程。
将测试脚本改成:
$pid = pcntl_fork(); if ($pid == -1){ ... } else if ($pid > 0){ echo "parent continue \n"; pcntl_wait($status); for ($k=0; $k<2; ++$k){ beep(); } } else if ($pid == 0){ ... }
用命令行运行
#php -f test.php
输出结果
parent start, pid 1807
1807 2013-01-14 15:20:05
parent continue
child start, pid 1808
1808 2013-01-14 15:20:06
1808 2013-01-14 15:20:07
1808 2013-01-14 15:20:08
1808 2013-01-14 15:20:09
1808 2013-01-14 15:20:10
1807 2013-01-14 15:20:11
1807 2013-01-14 15:20:12
parent continue
child start, pid 1809
1809 2013-01-14 15:20:13
1809 2013-01-14 15:20:14
1809 2013-01-14 15:20:15
1809 2013-01-14 15:20:16
1809 2013-01-14 15:20:17
1807 2013-01-14 15:20:18
1807 2013-01-14 15:20:19
child start, pid 1810
1810 2013-01-14 15:20:20
parent continue
1810 2013-01-14 15:20:21
1810 2013-01-14 15:20:22
1810 2013-01-14 15:20:23
1810 2013-01-14 15:20:24
1807 2013-01-14 15:20:25
1807 2013-01-14 15:20:26
父进程在pcntl_wait()将自己阻塞,等待子进程运行完了才接着运行。
3. 非阻塞方式
阻塞方式失去了多进程的并行性。还有一种方法,既可以回收已经结束的子进程,又可以并行。这就是非阻塞的方式。
修改脚本:
// example of multiple processes date_default_timezone_set( 'Asia/Chongqing'); declare (ticks = 1); pcntl_signal(SIGCHLD, "garbage" ); echo "parent start, pid ", getmypid(), "\n" ; beep(); for ($i=0; $i<3; ++$i){ $pid = pcntl_fork(); if ($pid == -1){ die ("cannot fork" ); } else if ($pid > 0){ echo "parent continue \n"; for ($k=0; $k<2; ++$k){ beep(); } } else if ($pid == 0){ echo "child start, pid ", getmypid(), "\n" ; for ($j=0; $j<5; ++$j){ beep(); } exit (0); } } // parent while (1){ // do something else sleep(5); } // *** function garbage($signal){ echo "signel $signal received\n" ; while (($pid = pcntl_waitpid(-1, $status, WNOHANG))> 0){ echo "\t child end pid $pid , status $status\n" ; } } function beep(){ echo getmypid(), "\t" , date( 'Y-m-d H:i:s', time()), "\n" ; sleep(1); }
用命令行运行
#php -f test.php &
输出结果
parent start, pid 2066
2066 2013-01-14 16:45:34
parent continue
2066 2013-01-14 16:45:35
child start, pid 2067
2067 2013-01-14 16:45:35
20662067 2013-01-14 16:45:362013-01-14 16:45:36
2067 2013-01-14 16:45:37
parent continue
2066 2013-01-14 16:45:37
child start, pid 2068
2068 2013-01-14 16:45:37
2067 2013-01-14 16:45:38
2068 2013-01-14 16:45:38
2066 2013-01-14 16:45:38
parent continue
2066 2013-01-14 16:45:40
child start, pid 2069
2069 2067 2013-01-14 16:45:40
2013-01-14 16:45:40
2068 2013-01-14 16:45:40
2066 2013-01-14 16:45:41
2069 2013-01-14 16:45:41
2068 2013-01-14 16:45:41
signel 17 received
child end pid 2067, status 0
2069 2013-01-14 16:45:42
2068 2013-01-14 16:45:42
2069 2013-01-14 16:45:43
signel 17 received
child end pid 2068, status 0
2069 2013-01-14 16:45:44
signel 17 received
child end pid 2069, status 0
多个进程又并行运行了,而且运行大约10秒钟之后,用 ps -ef | grep php 查看正在运行的进程,只有一个进程
lqling 2066 1388 0 16:45 pts/1 00:00:00 php -f t5.php
是父进程,子进程被回收了。
4. 子进程退出状态
pcntl_waitpid(-1, $status, WNOHANG) $status 返回子进程的结束状态
5. windows多线程
windows系统不支持pcntl函数,幸好有curl_multi_exec()这个工具,利用内部的多线程,访问多个链接,每个链接可以作为一个任务。
编写脚本 test1.php
date_default_timezone_set( 'Asia/Chongqing'); $tasks = array( 'http://localhost/feedbowl/t2.php?job=task1', 'http://localhost/feedbowl/t2.php?job=task2', 'http://localhost/feedbowl/t2.php?job=task3' ); $mh = curl_multi_init(); foreach ($tasks as $i => $task){ $ch[$i] = curl_init(); curl_setopt($ch[$i], CURLOPT_URL, $task); curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, 1); curl_multi_add_handle($mh, $ch[$i]); } do {$mrc = curl_multi_exec($mh,$active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { if (curl_multi_select($mh) != -1) { do {$mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } // completed, checkout result foreach ($tasks as $j => $task){ if (curl_error($ch[$j])){ echo "task ${j} [$task ] error " , curl_error($ch[$j]), "\r\n" ; } else { echo "task ${j} [$task ] get: \r\n" , curl_multi_getcontent($ch[$j]), "\r\n" ; } }
编写脚本 test2.php
date_default_timezone_set( 'Asia/Chongqing'); echo "child start, pid ", getmypid(), "\r\n" ; for ($i=0; $i<5; ++$i){ beep(); } exit (0); // *** function beep(){ echo getmypid(), "\t" , date('Y-m-d H:i:s' , time()), "\r\n"; sleep(1); }
用命令行运行
#php -f test1.php &
输出结果
task 0 [http://localhost/feedbowl/t2.php?job=task1] get:
child start, pid 5804
5804 2013-01-15 20:22:35
5804 2013-01-15 20:22:36
5804 2013-01-15 20:22:37
5804 2013-01-15 20:22:38
5804 2013-01-15 20:22:39
task 1 [http://localhost/feedbowl/t2.php?job=task2] get:
child start, pid 5804
5804 2013-01-15 20:22:35
5804 2013-01-15 20:22:36
5804 2013-01-15 20:22:37
5804 2013-01-15 20:22:38
5804 2013-01-15 20:22:39
task 2 [http://localhost/feedbowl/t2.php?job=task3] get:
child start, pid 5804
5804 2013-01-15 20:22:35
5804 2013-01-15 20:22:36
5804 2013-01-15 20:22:37
5804 2013-01-15 20:22:38
5804 2013-01-15 20:22:39
从打印的时间看到,多个任务几乎是同时运行的。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Alipay PHP ...

JWT는 주로 신분증 인증 및 정보 교환을 위해 당사자간에 정보를 안전하게 전송하는 데 사용되는 JSON을 기반으로 한 개방형 표준입니다. 1. JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성됩니다. 2. JWT의 작업 원칙에는 세 가지 단계가 포함됩니다. JWT 생성, JWT 확인 및 Parsing Payload. 3. PHP에서 인증에 JWT를 사용하면 JWT를 생성하고 확인할 수 있으며 사용자 역할 및 권한 정보가 고급 사용에 포함될 수 있습니다. 4. 일반적인 오류에는 서명 검증 실패, 토큰 만료 및 대형 페이로드가 포함됩니다. 디버깅 기술에는 디버깅 도구 및 로깅 사용이 포함됩니다. 5. 성능 최적화 및 모범 사례에는 적절한 시그니처 알고리즘 사용, 타당성 기간 설정 합리적,

세션 납치는 다음 단계를 통해 달성 할 수 있습니다. 1. 세션 ID를 얻으십시오. 2. 세션 ID 사용, 3. 세션을 활성 상태로 유지하십시오. PHP에서 세션 납치를 방지하는 방법에는 다음이 포함됩니다. 1. 세션 _regenerate_id () 함수를 사용하여 세션 ID를 재생산합니다. 2. 데이터베이스를 통해 세션 데이터를 저장하십시오.

PHP 개발에서 견고한 원칙의 적용에는 다음이 포함됩니다. 1. 단일 책임 원칙 (SRP) : 각 클래스는 하나의 기능 만 담당합니다. 2. Open and Close Principle (OCP) : 변경은 수정보다는 확장을 통해 달성됩니다. 3. Lisch의 대체 원칙 (LSP) : 서브 클래스는 프로그램 정확도에 영향을 미치지 않고 기본 클래스를 대체 할 수 있습니다. 4. 인터페이스 격리 원리 (ISP) : 의존성 및 사용되지 않은 방법을 피하기 위해 세밀한 인터페이스를 사용하십시오. 5. 의존성 반전 원리 (DIP) : 높고 낮은 수준의 모듈은 추상화에 의존하며 종속성 주입을 통해 구현됩니다.

시스템이 다시 시작된 후 UnixSocket의 권한을 자동으로 설정하는 방법. 시스템이 다시 시작될 때마다 UnixSocket의 권한을 수정하려면 다음 명령을 실행해야합니다.

phpstorm에서 CLI 모드를 디버그하는 방법은 무엇입니까? PHPStorm으로 개발할 때 때때로 CLI (Command Line Interface) 모드에서 PHP를 디버그해야합니다 ...

정적 바인딩 (정적 : :)는 PHP에서 늦은 정적 바인딩 (LSB)을 구현하여 클래스를 정의하는 대신 정적 컨텍스트에서 호출 클래스를 참조 할 수 있습니다. 1) 구문 분석 프로세스는 런타임에 수행됩니다. 2) 상속 관계에서 통화 클래스를 찾아보십시오. 3) 성능 오버 헤드를 가져올 수 있습니다.

PHP 개발에서 PHP의 CURL 라이브러리를 사용하여 JSON 데이터를 보내면 종종 외부 API와 상호 작용해야합니다. 일반적인 방법 중 하나는 컬 라이브러리를 사용하여 게시물을 보내는 것입니다 ...
