Có một số ví dụ phổ biến trong lập trình hàng ngày của chúng tôi, chẳng hạn như các tác vụ mà suy nghĩ PHP yêu cầu thực hiện liên tục, chẳng hạn như nghệ sĩ PHP... và PHP yii..., sẽ được gắn vào nền thông qua nohup để duy trì trạng thái hoạt động lâu dài. Tương tự như vậy, trong Workerman, một tiến trình được bắt đầu bằng cách sử dụng một lệnh tương tự như phpindex.php start, nhưng sự khác biệt là nó không cần phải được gắn kết và chạy trong nền bằng cách sử dụng nohup. Một số bạn có thể tự hỏi làm thế nào nó có thể được thực hiện? Để giải quyết mối quan tâm của bạn bè, hôm nay chúng tôi sẽ tập trung vào việc phân tích sâu hơn về cách triển khai Workerman daemon.
Hãy bắt đầu với một số kiến thức liên quan đến quy trình:
Parent process: Tiến trình cha là tiến trình tạo ra các tiến trình khác. Khi một tiến trình tạo ra một tiến trình khác, người tạo được gọi là tiến trình cha và tiến trình được tạo ra trở thành tiến trình con. Tiến trình cha có thể xác định tiến trình con mà nó tạo ra bằng cách sử dụng Process Identifier (PID). Child process: Một tiến trình con là một tiến trình mới được tạo ra bởi tiến trình cha. Một tiến trình con thừa hưởng một số thuộc tính của tiến trình cha, chẳng hạn như biến môi trường, bộ mô tả tệp, v.v. Một tiến trình con chạy độc lập với tiến trình cha của nó, có thể thực thi mã riêng và có tài nguyên và không gian bộ nhớ riêng. Process Group: Một process group là một tập hợp các process liên quan. Mỗi nhóm quy trình có một ID nhóm quy trình duy nhất (PGID) được sử dụng để xác định nhóm quy trình đó. Process group thường được tạo ra bởi tiến trình cha và bao gồm tất cả các tiến trình con có cùng ID phiên (SID) như tiến trình cha. Session là một tập hợp các quá trình liên quan, thường bắt đầu khi người dùng đăng nhập vào hệ thống và kết thúc khi người dùng đăng xuất hoặc đóng thiết bị đầu cuối. Các tiến trình trong một session chia sẻ cùng một control terminal. Mỗi session có một Session ID (SID) duy nhất để xác định session. Một session thường chứa một hoặc nhiều process group và process group đầu tiên trở thành master process group của session.
Thường được gọi là văn xuôi tám chân, những khái niệm này không bao giờ dễ hiểu. Hãy xem một ví dụ. Sau khi thực hiện lệnh "php-index". PHP"tạo ra tiến trình 61052. Quá trình cha của quá trình này là Bash Process 8243, vì vậy đừng lo lắng ở đây. Sau đó, tiến trình con 61053 được tạo thông qua Fork, với tiến trình cha là 61052. Hai tiến trình này có chung một nhóm tiến trình 61052 và phiên 8243. Gọi hàm posix_setsid sẽ mở ra một process group mới 61053 và một session mới 61053 cho subprocess 61053, trong đó session có thể được hiểu là terminal cửa sổ lệnh mới. Cuối cùng, tiến trình con 61053 tạo tiến trình con 61054 thông qua Fork và tiến trình 61053 được nâng cấp lên tiến trình cha. Lý do để sử dụng Fork một lần nữa là để tránh liên kết với các quá trình được điều khiển bởi thiết bị đầu cuối. Quá trình 61052 được tạo ở chế độ Terminal và từ đó tiến trình 61054 tạo thành một daemon.
[ manongsen@root phpwork]$ php index.php
[parent] Process ID: 61052, Parent Process ID: 8243, Process Group ID: 61052, Session ID: 8243
[parent1] Process ID: 61052, parent process ID: 8243, process group ID: 61052, session ID: 8243 exited the process
[child1] Process ID: 61053, parent process ID: 61052, process group ID: 61052, session ID: 8243
[child1] Process ID: 61053, parent process ID: 61052, process group ID: 61053, session ID: 61053
[parent2] Process ID: 61053, parent process ID: 61052, process group ID: 61053, session ID: 61053 exited the process
[child2] Process ID: 61054, parent process ID: 61053, process group ID: 61053, session ID: 61053. This process is retained [ manongsen@root phpwork]$ ps aux | grep index.php
Root 66064 0.0 0.0 408105040 1472 s080 S+10:00 PM 00:00 grep index.php
Root 61054 0.0 438073488 280?? S 10:00 PM 00:00 PHP index.php
Thông tin quy trình trên được tạo ra bằng cách thực hiện mã này. Nếu bạn đọc kỹ đoạn mã này, bạn sẽ thấy tại sao hàm posix_setsid không được gọi trước Fork đầu tiên mà sau Fork thứ hai. Bằng cách này, bạn không cần phải sử dụng Fork hai lần? Lý do là quá trình leader không thể tạo một session và process group ID 61052 giống với process ID 61052, có nghĩa là process hiện tại là leader process. Do đó, một quy trình con là cần thiết để tạo một phiên mới, đòi hỏi sự chú ý đặc biệt.
<? php function echoMsg($prefix, $suffix="") {
//Process ID
$pid = getmypid(); //Process group ID
$pgid = posix_getpgid($pid);
//Session ID
$sid = posix_getsid($pid); //Parent process ID
$ppid = posix_getppid(); Echo "[{$prefix}] Process ID: {$pid}, Parent Process ID: {$ppid}, Process Group ID: {$pgid}, Session ID: {$sd} {$Suffix}". PHP_EOL;
} //[parent] Process ID: 61052, Parent Process ID: 8243, Process Group ID: 61052, Session ID: 8243
echoMsg("parent"); //The first Fork process
$pid = pcntl_fork();
if ( $pid < 0 ) {
exit('fork error');
} else if( $pid > 0 ) {
//[parent1] Process ID: 61052, parent process ID: 8243, process group ID: 61052, session ID: 8243 exited the process
Echoes ("parent1", "exited the process");
exit;
} //The child process ID created is 61053, but the process group, session, and parent process are still the same
//[child1] Process ID: 61053, parent process ID: 61052, process group ID: 61052, session ID: 8243
echoMsg("child1"); //Calling the posix_setsid function will create a new session and process group, and set the process group ID and session ID to that process ID
if (-1 === \posix_setsid()) {
throw new Exception("Setsid fail");
} //Now you will find that both the process group ID and session ID have changed to 61053, which is equivalent to starting a session window similar to a Linux terminal
//[child1] Process ID: 61053, parent process ID: 61052, process group ID: 61053, session ID: 61053
echoMsg("child1"); //Second Fork Process
//The reason for requiring a secondary Fork process here is to avoid being associated with terminal controlled processes. This process 61052 was created in terminal mode
//Need to detach from process 61052 to ensure the stability of the daemon process
$pid = pcntl_fork();
if ( $pid < 0 ){
exit('fork error');
} else if( $pid > 0 ) {
//[parent2] Process ID: 61053, parent process ID: 61052, process group ID: 61053, session ID: 61053 exited the process
Echoes ("parent2", "exited the process");
exit;
} //At this point, the process has broken free from the control of the terminal process and formed a daemon process
//[child2] Process ID: 61054, parent process ID: 61053, process group ID: 61053, session ID: 61053. This process is retained
Echoes ("child2", "This process is reserved"); sleep(100);
Điều này là tốt nhất cho những người bạn có thời gian để thực hiện mã và tự phân tích vì sẽ có những phần thưởng khác nhau. Giả sử bạn đã thực hành ở đây, chúng ta hãy nhìn vào static::daemon() hàm trong phương thức runAll ở dòng 554 của tệp Workerman.php. Logic của quá trình thực hiện gần giống với ví dụ trên. Tuy nhiên, hàm umask cũng được sử dụng ở đây, chức năng chính của nó là cấp quyền tương ứng cho tệp hoặc thư mục được tạo bởi quá trình, đảm bảo có quyền hoạt động trên tệp hoặc thư mục. // workerman/Worker.php:554 /**
- Run all worker instances. *Run process
- @return void */ public static function runAll() { static::checkSapiEnv(); static::init(); static::parseCommand(); static::lock(); //Create a process and form a daemon process static::daemonize(); static::initWorkers(); static::installSignal(); static::saveMasterPid(); static::lock(\LOCK_UN); static::displayUI(); static::forkWorkers(); static::resetStd(); static::monitorWorkers(); }
// workerman/Worker.php:1262 /**
- Run as daemon mode. *Run in daemon mode
- @throws Exception */ protected static function daemonize() { //Determine whether it is already in a guarded state and whether the current system is in a Linux environment if (! static::_OS !== \OS_TYPE_LINUX) { return; }
//If umask is set to 0, the file permissions created by the current process will be 777, which has the highest permission \umask(0);
//The first time creating a process $pid = \pcntl_fork(); if (-1 === $pid) { //Process creation failed throw new Exception('Fork fail'); } elseif ($pid > 0) { //Main process exits exit(0); }
//The child process continues to execute //By calling the posix_setsid function, a process can detach from its parent process and transform into a daemon process if (-1 === \posix_setsid()) { throw new Exception("Setsid fail"); }
//The second creation process, in a System V based system, exits by forking the parent process again //Ensure that the formed daemon process does not become the first session process and does not have control terminals $pid = \pcntl_fork(); if (-1 === $pid) { //Process creation failed throw new Exception("Fork fail"); } elseif (0 !== $pid) { //Main process exits exit(0); }
//The child process continues to execute } Daemon cũng là một phần quan trọng của Workerman, đảm bảo sự ổn định của quá trình Workerman. Không giống như các lệnh mà chúng ta khởi chạy thông qua nohup, nohup đôi khi treo trong nền mà không ai chú ý, bạn bè có thể đã trải qua điều này. Tất nhiên, cũng có một số phần mềm quản lý daemon mã nguồn mở trên thị trường như supervisors và một số sử dụng các thiết bị đầu cuối phiên như screen và tmux để triển khai chúng. Trên thực tế, có rất nhiều cách để thực hiện daemon. Ở đây, chúng tôi chỉ giới thiệu một ví dụ về việc triển khai chế độ daemon trong PHP để phân tích các nguyên tắc triển khai daemon trong Workerman. Chúng tôi hy vọng nội dung này đã giúp bạn.
Nếu bạn muốn trải nghiệm phiên bản PHP mới hoặc chuyển đổi phiên bản PHP, hãy sử dụng Servbay để triển khai môi trường phát triển PHP. Đây là sản phẩm tôi đang phát triển và tôi sẽ duy trì công cụ này trong một thời gian dài.