Categories
PHP Programming

PHP Dark Arts: Multi-Processing (Part 1)

Note:  Part 2 of this post can be found here.

Of all the glorious programming languages in existence, you’ve chosen to work with PHP.  Okay, maybe you were forced to, but that doesn’t mean you can’t have fun right?  Hmm, fun… What’s fun?  Threading, race conditions, and deadlocks.  Sounds like loads of fun!  But alas, PHP doesn’t have functionality to cover this.  True, but the host operating system does.  We can just fork processes manually like in the good ‘ole days and then ride off into the sunset.  But we shouldn’t do that, it’s wrong.  It’s taking advantage of PHP.  Bah! We’re going to do it anyways.  And FOR THE LOVE OF GOD, do not do this in production code.  If you need multi-threading, use a different language.

Process Control

One of those things that you are bound to learn about if you go through a computer science degree is process control.  Process control usually comes up slowly and then bites you in the ass REALLY hard during operating systems courses.  Thinking about race conditions, deadlocks, and collisions are all part of the game.  And guess what?  When you are writing multi-threaded programs this is exactly the type of thing you will encounter.

When thinking about process control, people often cite some form of a producer-consumer problem.  You have one process (thread) producing information, and another thread consuming it.  For instance, a producer may spit out a stream of integers, and the consumer will, well, consume them.  However, the consumer will terminate itself when it hits a non-integer character.  That’s called out exit condition, and it’s very important.  You have to always remember to have some sort of fool-proof exit condition, otherwise the process is going to hang and go zombie on your.  If your program get’s executed a few thousand times a day, you get a few thousand zombies (process zombie apocalypse!).  So, the import part here is to remember that you need to have exit condtions.

Getting Started

The first step into multi-threading in PHP is making sure your build is compiled with the –enable-pcntl flag set.  If that’s not set, you’re dead in the water.  Otherwise, we can take a look at a simple example.

1
2
3
4
5
6
$processID = pcntl_fork();
if($processID) {
     echo "I'm in the parent process!";
} else {
     echo "I'm in the child process!";
}

Now, a quick explanation.  The pcntl_fork() function takes the current running process and makes a copy of it.  Everything (for practical purposes) is copied into this new child process except the process id(pid) which is changed to something new.  This is where things get a bit weird.  When pcntl_fork() executes, the pid of the child process is returned to the parents thread of execution.  A value of 0(zero) is returned to the child process’ thread of execution.  Since you can differentiate between threads of execution, you can make them do different things with a simple if statement like above.  So what does this program print?

I'm in the parent process!
I'm in the child process!

or

I'm in the child process!
I'm in the parent process!

It can actually go either way here.  It depends entirely on how your operating system decided to schedule the processes.  But remember, the child process is an exact (not entirely true, but let’s go with it) copy of the parent process.  So what happens if we change the code a bit.

1
2
3
4
5
6
7
$processID = pcntl_fork();
if($processID) {
     echo "I'm in the parent process!";
} else {
     echo "I'm in the child process!";
}
echo "End of the line folks.";

Since the last echo statement exists in both parent and child processes, you’ll get:

I'm in the parent process!
End of the line folks.
I'm in the child process!
End of the line folks.

Waiting for the Child

One of the problems that you run in to with writing multi-threaded programs is that the child process can finish before the parent, or the parent can finish before the child.  You just never really know.  So you need a way to wait for processes to finish.  Lucky for us, PHP at least provides this functionality for us.

1
2
3
4
5
6
7
$pid=pcntl_fork();
if($pid) {
     pctnl_waitpid($pid,$status,WUNTRACED);
     echo "In parent process!";
} else {
     echo "In child process!";
}

By using the pcntl_waitpid() function, we can force the parent process to wait for the child process to finish executing.  This is handy for if you have a critical procedure that your child process must complete before the parent can continue.  In our case, the output will always be:

In child process!
In parent process!

Next Time…

That’s all for now, but soon I’ll have The 2nd (and last) part of this article up for your enjoyment.  In that part, we’ll cover some more advanced notions like getting/setting priority, setting alarms, and signal processing.   You should follow me on Twitter and/or become a fan on Facebook to find out when this exciting(?) article comes out.

By Jack Slingerland

Founder of Kernl.us. Working and living in Raleigh, NC. I manage a team of software engineers and work in Python, Django, TypeScript, Node.js, React+Redux, Angular, and PHP. I enjoy hanging out with my wife and son, lifting weights, and advancing Kernl.us in my free time.

18 replies on “PHP Dark Arts: Multi-Processing (Part 1)”

Technically pnctl_fork kicks off a new process, so it’s multi-process not multi-threading.

Also it’s also worth noting that the function is only available from the CLI SAPI, and is not accessible from FastCGI process or mod_php.

Very true. Forking web server processes would probably go very poorly. You’re also not the first person to mention the process vs thread issue. I’ve updated the title to reflect a more accurate view.

Thanks for visiting!

“And FOR THE LOVE OF GOD, do not do this in production code. If you need multi-threading, use a different language.”

Perhaps such a blanket statement is a bit over the top? Quite often, PHP is perfectly suited for this. As this this is not really multi-threading (as someone above mentioned), it can be perfectly safe to use process control in PHP.

Used correctly, process control can really help speed up tasks where a bunch of data is collected into an object, then distributed across different processes for independent processing, and then pulled back together in the parent process for collation and further processing.

Why do this in another language when PHP does it perfectly well?

I’ll concede that it’s a bit over the top, however, it is a much harder way of doing multiple things. Using a language that has good threading support (Python for instance), is almost always a better choice then trying to bend PHP to your will.

To each their own I suppose.

[…] Multi Threading in PHP (2 teilig) – Ebenfalls wieder was mit eher akademischem Hintergrund. Wer sich in die Prozessverwaltung etwas einarbeiten will, findet hier ‘ne nette Grundlage um zu experimentieren Dieser Beitrag wurde unter Datenbanken, Persönlich, php, webdev veröffentlicht. Setze ein Lesezeichen auf den Permalink. ← Web-Performance: Best Practices Quicktip: Integer Validation → […]

When you’ve reached the PHP dark arts index and realized that your interested in most of the topics. Then only to figure out that each topic begs of you not to actually use any exercise in a production setting, YOU KNOW YOU’VE REACHED THE UPPER LIMITS OF PHP. From that point you may may wonder what’s next. For me Python is the answer. Thanks

I couldn’t agree more. Python is my go-to language for most things now, although PHP is still great for rapid prototyping.

Just an update, to my first comment. First, Python is amazing. That said, PHP’s vision is being overwritten. PHP5 can do things outside the scope of a traditional website much like one would expect in a Python web application. Even though this article is a little dated, the cautions hold true. In a couple years though, PHP might be a whole different beast.

This is great, thank you. This is perfect for my prototype. I will man up and write my production code in a real language, but for the moment, this is exactly what I need.

Comments are closed.