2010-02-16 34 views
8

Tôi đang cố gắng viết một tập lệnh tạo ra một số quy trình con được chia nhỏ bằng cách sử dụng pcntl_* functions.PHP forking và nhiều tín hiệu con

Về cơ bản, có một tập lệnh chạy trong vòng lặp khoảng một phút, định kỳ thăm dò ý kiến ​​cơ sở dữ liệu để xem có nhiệm vụ nào để chạy hay không. Nếu có một, nó sẽ ngã ba và chạy nhiệm vụ trong một quá trình riêng biệt để cha mẹ không được tổ chức bởi một nhiệm vụ chạy dài.

Vì có thể có một số lượng lớn các tác vụ sẵn sàng để chạy, tôi muốn giới hạn số lượng quy trình con được tạo. Vì vậy, tôi theo dõi số lượng các quá trình bằng cách tăng một biến mỗi lần một được tạo ra (và sau đó tạm dừng nếu có quá nhiều), và sau đó giảm nó trong một trình xử lý tín hiệu. Loại như thế này:

define(ticks = 1); 

$openProcesses = 0; // how many we have open 
$max = 3;   // the most we want open at a time 

pcntl_signal(SIGCHLD, "childFinished"); 

while (!time_is_up()) { 
    if (there_is_something_to_do()) { 
     $pid = pcntl_fork(); 
     if (!$pid) {  // I am the child 
      foo();  // run the long-running task 
      exit(0);  // and exit 
     } else {   // I am the parent 
      ++$openProcesses; 
      if ($openProcesses >= $max) { 
       pcntl_wait($status); // wait for any child to exit 
      }       // before continuing 
     } 
    } else { 
     sleep(3); 
    } 
} 

function childFinished($signo) { 
    global $openProcesses; 
    --$openProcesses; 
} 

này hoạt động khá nhiều ok hầu hết thời gian, trừ khi hai hay nhiều quá trình hoàn thành cùng một lúc - chức năng xử lý tín hiệu chỉ được gọi một lần, mà ném ra truy cập của tôi. Lý do cho điều này được giải thích bằng "Ẩn danh" trong số notes of the PHP manual:

Nhiều trẻ em trả lại ít hơn số trẻ em thoát tại một thời điểm nhất định Tín hiệu SIGCHLD là hành vi bình thường đối với hệ thống Unix (POSIX). SIGCHLD có thể được đọc là "một hoặc nhiều trẻ em thay đổi trạng thái - đi kiểm tra con của bạn và thu hoạch các giá trị trạng thái của chúng".

Câu hỏi của tôi là: Làm cách nào để kiểm tra trẻ em và thu thập trạng thái của chúng? Có cách nào đáng tin cậy để kiểm tra xem có bao nhiêu tiến trình con được mở tại bất kỳ thời điểm nào không?

Sử dụng PHP 5.2.9

+0

có thể chỉ sử dụng https://www.rabbitmq.com/ sẽ khiến toàn bộ mọi thứ dễ bị lỗi hơn –

Trả lời

0

Bạn có thể có con gửi SIGUSR1 cho phụ huynh khi họ bắt đầu, sau đó một SIGUSR2 trước khi thoát. Một thứ khác mà bạn đang xử lý khi sử dụng các tín hiệu nguyên thủy là hạt nhân hợp nhất chúng, mà nó không làm với các tín hiệu RT. Về lý thuyết, bất kỳ tín hiệu không rt nào cũng có thể được hợp nhất.

Bạn có thể thực hiện một số loại khóa đơn giản bằng cách sử dụng sqlite, trong đó chỉ có một đứa trẻ tại một thời điểm có thể có thanh nói. Chỉ cần đảm bảo rằng trẻ em xử lý tín hiệu bình thường gây tử vong để chúng vẫn còn sống để giải phóng khóa.

2

Một cách là giữ một mảng các PID của các tiến trình con, và trong trình xử lý tín hiệu kiểm tra từng PID để xem liệu nó có đang chạy hay không. Mã (chưa được kiểm tra) sẽ trông giống như:

define(ticks = 1); 

$openProcesses = 0; 
$procs = array(); 
$max = 3; 

pcntl_signal(SIGCHLD, "childFinished"); 

while (!time_is_up()) { 
    if (there_is_something_to_do()) { 
     $pid = pcntl_fork(); 
     if (!$pid) {  
      foo();   
      exit(0);  
     } else {   

      $procs[] = $pid; // add the PID to the list 

      ++$openProcesses; 
      if ($openProcesses >= $max) { 
       pcntl_wait($status);  
      }       
     } 
    } else { 
     sleep(3); 
    } 
} 

function childFinished($signo) { 

    global $openProcesses, $procs; 

    // Check each process to see if it's still running 
    // If not, remove it and decrement the count 
    foreach ($procs as $key => $pid) if (posix_getpgid($pid) === false) { 
     unset($procs[$key]); 
     $openProcesses--; 
    } 

} 
Các vấn đề liên quan