I've looked around for this and I can't seem to find anyone who is trying to do exactly what I am.
I have information that is passed in to my function via a _POST request. Based on that data, I run an exec command to run a TCL script a certain number of times (with different parameters, based on the post variable). Right now, I have the exec in a foreach so this takes forever to run (the TCL script takes 15 or so seconds to come back, so if I need to run it 100 times, I have a bit of an issue). Here is my code:
public function executeAction(){
//code to parse the _POST variable into an array called devices
foreach($devices as $devID){
exec("../path/to/script.tcl -parameter1 ".$device['param1']." -parameter2 ".$device['param2'], $execout[$devID]);
}
print_r($execout);
}
Obviously this code is just an excerpt with big chunks removed, but hopefully it's enough to demonstrate what I'm trying to do.
I need to run all of the execs at once and I need to wait for them all to complete before returning. I also need the output of all of the scripts stored in the array called $execout.
Any ideas?
Thanks!!!
Quoting PHP Documentation :
So, you can exec in background if you redirect the output in a file :
But if you want to wait that ALL execs are finished before continuing, you have to make a call back from the external script. Maybe like this :
Like this, your callback.php script will be called after every execs of script.tcl.
Maybe you can do something with these tricks.
PHP's exec function will always wait for a response from your execution. However you can send the stdout & stderror of the process to /dev/null (on unix) and have these all the scripts executed almost instantly. This can be done by adding..
To the end of your execution string.
But! that means they'll fork off and finish processing independently. It may be worth having them write a response back somewhere. And you could create a listener to pick this up and process it.
If you put your
exec()
call in a separate script, you can call that external script multiple times in parallel usingcurl_multi_exec()
. That way, you'd make all the calls in separate requests, so they could execute simultaneously. Poll&$still_running
to see when all requests have finished, after which you can collect the results from each.Update: Here's a blog post detailing exactly what I'm describing.
Example
Based on the blog post linked above, I put together the following example.
Script being run in parallel:
Script making calls in parallel:
Here is some output I received when running it a few times:
Hope that helps!
One side note: make sure your web server can process this many parallel requests. If it serves them sequentially or can only serve very few simultaneously, this approach gains you little or nothing. :-)
You need to modify your script a bit
Look at ExecFuture andFutureIterator in the libputil library:
https://secure.phabricator.com/book/libphutil/class/ExecFuture/
It does exactly what you need with a pretty nice syntax: