Multiprocessing part 1: Quick & Dirty

DEC Alpha AXP 21064 microprocessor

DEC Alpha AXP 21064 microprocessor

PHP can do only one thing at a time. Usually (for websites) this isn’t a big problem because you only have to process a request. On the other hand, if you are doing something more time-consuming PHP could be to slow.

An example is my chat bot server (Mai Ocean). For each conversation I have to make a connection with a server, so for each conversation I have a socket that I have to listen and write to. So if 10 people are talking to my bot I have at least 11 socket connections (10 conversations + main server), you could imagine that this would be way to much for just one script. So how can we solve this?

With multiprocessing! Multiprocessing is a method to run multiple processes and give each of them a task to do. In the following weeks I am going to write about different ways to implement multiprocessing:

  1. Part 1: Quick & Dirty (using exec())
  2. Part 2: Parent & Childs (using PCNTL)
  3. Part 3: Communication (using proc_open())

Today I will cover the first part and will talk about the easiest method using exec(). This method is very simple but you cannot do much with it. Anyway, lets begin: First of all we should create a parent process. No matter what method you use you always have to create a parent. The parent process creates all the child processes and can differ from its children but can also be the same.

Today our child processes differs from the parent because we have to add some code to our parent to start up its children. A simple diagram of our program could look like this:

As you see we have one parent process and three children. For this article I will use only one child script to make it easier. So before we look at creating child processes we first have to write a child script. Your child script can do and contain anything you want but it must be possible to run it from the command line.

For the rest of the article I will be using the following child script and name it child.php:

< ?php
date_default_timezone_set('Europe/Amsterdam');
sleep(2);
echo date("H:i:s");
?>

The child will first wait for two seconds and then output the current time. You should note that this child exits by itself, that is something to remember for next time. Now we have a child we can create the parent script. In this example the parent should only start its children and then exit:

< ?php
for($i = 0; $i < 5; $i++)
{
	echo "Starting child $i\n";
	echo exec("php child.php") . "\n";
}

Now save the code (for example as parent.php) and run it from the command line. If everything works you should see something like the following:

$ php test.php
Starting child 0
20:34:00
Starting child 1
20:34:02
Starting child 2
20:34:04
Starting child 3
20:34:06
Starting child 4
20:34:08

Now how does this work? The parent uses the exec() function to start up a child. As a parameter we used the command php and the name of our child child.php. exec() will run the command and return the last line from the result. In our example this is the current time. Of course you could also add some arguments to the command to interact with the child script.

If you look closely you see that there is an 2 seconds interval between each start of a child. This is caused by the sleep function of each child. In other words our parent script has to wait for the child to complete before it can continue. When you need multiprocessing you do not want this because you do not have any profit from it. So how can we fix this? As stated on php.net:

If a program is started with this function, in order for it to continue running in the background, the output of the program must be redirected to a file or another output stream. Failing to do so will cause PHP to hang until the execution of the program ends.

Therefore if we want to let our children run in the background we have to direct the output, this can easily be done by changing the command:

exec("php child.php > /dev/null &");

The code above will send all output to /dev/null and there it will disappear. When you use this method the script runs in the background and will not let the parent wait. The parent will start 5 children without waiting for the first to finish.

NOTE: The method above does not work on Windows! It will only work on Unix systems. If you want to use it on Windows you should use another method. A possible solution is replacing the exec() command with pclose(popen("start /B ". $cmd, "r")); but I did not test it myself.

What do we have so far? We have a parent script that starts up 5 children that run in the background. The children in this case are useless because they output to /dev/null and you will never see that. Nevertheless you should be able to create more useful child scripts for yourself. For example: each script could backup a different database or file.

With the above you should be able to create programs that implement a form of simplistic multiprocessing. To make it all a bit better (and more difficult) we should let the parent and children communicate with each other. There is only one problem: the method we used here is not really useful when we need communication. This is because we cannot interact with the scripts directly, to do this we need another method (which I am going to discuss in the following articles).

If you still want to use this method (because you have not yet read my following article or I didn't finish it yet ;) ) you can use files. For example (from a previous version of my bot server) a conversation script checked every 2 seconds if there was a 'server-stop' file present in the temp directory of my application. When the file was present the child would close the socket and exit by itself. The reason why I am not going to explain this is because it is ugly and I want to forget that I every used it :P .

So in conclusion, we have looked at exec() which is a function to execute commands and used it to start child processes. This way is useful if you need it fast and do not have the time to create a better method. In the next part I am going to explain a more advanced method of creating parent and child processes.

See you next time! :)

Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • email
  • Hyves
  • LinkedIn
  • Live
  • MySpace
  • Netvibes
  • PDF
  • Reddit
  • StumbleUpon
  • Technorati
  • Twitter
  • Add to favorites
  • NuJIJ
  • RSS

Tags: , , , , , , , , , , ,

Leave a comment