Is PHP supporting multithreading? The answer is NO, if you are excluding the interop mechanism.
First of all, let me tell you a story about Threading: a CPU can have one or multiple cores. Each core can have one or multiple processes spawned by applications which in turn can be forked with child processes. Each process / child process can have one or multiple threads which are “the smallest unit of processing that can be scheduled by an operating system” (Wikipedia). Further down, Microsoft comes with a concept of task, which is included in the latest version of the .NET Framework – Parallel Framework (PFX).
For Unix we have http://www.php.net/manual/en/intro.posix.php and http://www.php.net/manual/en/intro.pcntl.php which are a set of complementary libraries that allows process manipulation operations. Let me repeat that: “process manipulation operations”… since there is nothing mentioned about threading, you can simply put it this way: PHP doesn’t natively support threading in Unix through the libraries mentioned above, but rather it supports process forking. As you may already noticed, I used the term of “natively” because you can achive multithreading by interoping with languages like Java, C / C++ or even .NET through Mono. If you wonder what are the advantages of using threads over processes in general, read this http://www.programmerinterview.com/index.php/operating-systems/thread-vs-process/; in particular, each language can have it’s own mechanisms of dealing with threads. A nice article on “multithreading” in PHP can be found on my comrade’s blog Tudor a.k.a. motanelu http://blog.motane.lu/2009/01/02/multithreading-in-php/.
Since posix and pcntl libraries are not supported on Windows, I’m going to assume that some of you who are running PHP under Apache / IIS on Windows will still want at some point to multithread the application. Have no fear, .NET is here! If you are familiar with C#, VB.NET or maybe F#, you can easily take advantage of the interoperability between PHP and .NET through the DOTNET class http://www.php.net/manual/en/class.dotnet.php and with it of all the goodies that the .NET Framework 4.0 is made of: PLINQ, Parallel class, task parallelism, concurrent collections and other. Make no mistake, as I already mentioned, the interop mechanism can be also used from Unix in pair with some languages, but since I primarily am a .NET programmer, I’m going to explain this through C# code.
I will assume that you have installed at least Visual C# 2010 Express Edition. First create a new Class Library project: File -> New Project -> Class Library. We’re going to call it MultithreadedDotNetClass. The purpose of this library is to add random numbers from multiple threads, avoiding duplicates. I will attach the source code here http://goo.gl/1so4v
In order to install the new assembly in the GAC, so that we could use it with the DOTNET PHP class, we need to sign it with a strong name. You can either do this from the IDE or with the SN tool from the .NET SDK. I will do this from the IDE, by going to Project -> MultithreadedDotNetClass Properties… -> Signing -> Sign the assembly.
Before building the library, I will make this assembly visible to COM components by setting the [assembly: ComVisible()] attribute to true (by default is false). Now you can finally build it.
Now let’s install our assembly in the GAC. Open a new command prompt, go to the location where gacutil is installed and type the following:
gacutil -I "C:\Path\To\The\Library\MultithreadedDotNetClass.dll"
For the test create a new PHP file, test.php, with the following content, replacing the Version / PublicKeyToken with your own:
$multithreadedDotNetObject = new DOTNET('MultithreadedDotNetClass, Version=22.214.171.124, Culture=neutral, PublicKeyToken=b9137eaca16ad247', 'MultithreadedDotNetClass.Program'); $multithreadedDotNetObject->DoWork();
If you have trouble in finding the Version / PublicKeyToken for the MultithreadedDotNetClass assembly, type this in the command prompt:
gacutil /lr MultithreadedDotNetClass
The result will be the Strong Name of the assembly:
After running our test, the output is as expected: