How does pcntl_fork work in PHP?

user1432856 picture user1432856 · Jun 3, 2012 · Viewed 21.2k times · Source

I'm confused about pcntl_fork in PHP.

I think it does multi-threading, but how does it work and how would I use it in a script?

Answer

Martin Strouhal picture Martin Strouhal · Oct 28, 2012

PCNTL can not make threads. It only "forks" current PHP process. What does it mean? When you call pcntl_fork(), current process is split into two processes. Whole namespace of parent process is copied into the child and both processes continue with execution in parallel with only one difference: pcntl_fork() returns child's PID in parent and 0 in child.

Some hints:

  • It is disabled by default. If you manage to enable it, then do it for CLI only. Never ever use it with web server! It will behave in non-deterministic way. It can also bring whole machine down. Please, leave it disabled and read on.
  • Communication between processes is possible but horrible (via serialized object in shared memory).
  • File descriptors (and database connections) are shared, this causes problems very often. You have to reconnect your DB after forking or you will get errors like MySQL server has gone away from all forked processes when first of them closes the connection.
  • Parent process have to wait for children to finish or it will leave zombie processes consuming system resources behind.

Here's example from documentation:

<?php

$pid = pcntl_fork();
if ($pid == -1) {
     die('could not fork');
} else if ($pid) {
     // we are the parent
     pcntl_wait($status); //Protect against Zombie children
} else {
     // we are the child
}

But remember, PHP is just scripting language. It's not designed for parallel computing. You could do better job with simultaneously running CRONs, message queues or program in lower-level language, depending on your needs.

Forked PHP program is very hard to read, understand and debug. Maintaining that program will be a nightmare.

Don't make mistake and avoid forking. You don't need it. What you really need is asynchronous task runner. Good news, there is RabbitMQ and nice tutorial ;-) You can also try promising RabbitMQ library called Bunny

PS: Using message queues instead of forking gives you one more advantage. You can process the queue with multiple servers and scale horizontally as your traffic grows.

EDIT 2019-03-07

I have played a lot with asynchronous concurrency framework amphp and I have to mention it here. If you really need to run async non-blocking tasks in single request, I consider amphp to be the best solution today. It uses concept of php generators ($value = yield $promise) to execute human-readable code without reactphp-like promise hell.

https://amphp.org/