When Parallel::Loops
is combined with Win32::OLE
to create multiple instance of Matlab, if we use
my $ML = Win32::OLE->new('Matlab.Application') or die "Cannot start MATLAB"
in each loop, the program crashes showing an unhandled exception.
If drop the my
before $ML
then it works, but at any time only one instance is running.
I'm not sure what is the benefit of creating multiple MATLAB COM servers in a parallel loop.
By default the server is created in shared mode, ie shared by all instances. The MATLAB engine is exposed to the user as single-threaded, so in your case all the clients computations are run in serial, not in parallel.
Fortunately you create MATLAB COM server in dedicated mode:
Win32::OLE->new('Matlab.Application.single')
See this page for more info
PS: I know very little Perl :)
You really should show your full code.
If you are setting my $ML
inside the anonymous subroutine passed to Parallel::Loops
then you are setting the value in only a child process and the value will no be available to the parent.
It is unclear what you are using the Matlab
processes for, but they will not persist after the death of their parent, which is one of the child processes that your main program starts.
You could try declaring my @matlabs
outside the loop, and then doing
push @matlabs, Win32::OLE->new('Matlab.Application')
within the loop. But if you a number of persistent Matlab
processes then why not just run a simple for
loop?
Parellel::Loop are tested not working with Win32::OLE to start multiple instance of Matlab, but Parellel::Forkmanager works by using the "single" trick from Amro and clue from http://www.perlmonks.org/bare/?node_id=894058 for an error of "CoInitialize has not been called":
before the loop use:
use Win32::OLE; # qw(EVENTS); #Win32::OLE(0.1709) error 0x800401f0: "CoInitialize has not been called"
Win32::OLE->Initialize();
and inside the loop use:
my $ML = Win32::OLE->new('Matlab.Application.single') or die "Cannot start MATLAB";
$ML->{'Visible'}=0;
$ML->Execute('try;cd \''.$wkdir.'\';'.$executable.' '.$file.' '.$countfile.';catch;end;quit;');
The purpose of use OLE instesd of just using:
system('matlab -automation -wait -r "try;cd \''.$wkdir.'\';'.$executable.' '.$file.' '.$countfile.';catch;end;quit;');
is to hide the Matlab window, we just want it to do the work but we get the honor. Using Perl to achieve the parallellized matlab parfor effects we can keep all the available CPU busy doing tasks allocated before the parellel loop and collect/combine the results after that loop.
With further experiment, it is found that the error of Parallel::Loop and the error of Win32::OLE(0.1709) error 0x800706be: "The remote procedure call failed or Free to wrong pool when using Parellel::ForkManager can be both avoided by a suggestion from http://www-01.ibm.com/support/docview.wss?uid=swg21261292 and http://search.cpan.org/~gsar/libwin32-0.191/OLE/lib/Win32/OLE/TPJ.pod about silence the warning. All the code need to be included inside the parallel loop, and this are the working version:
require Win32::OLE;
import Win32::OLE;
Win32::OLE->Initialize();
no warnings qw(once);
$Win32::OLE::Warn = 0;
my $ML = Win32::OLE->new('Matlab.Application.single') or die "Cannot start MATLAB";
$ML->{'Visible'}=0;
$ML->Execute('try;cd \''.$wkdir.'\';'.$executable.' '.$file.' '.$countfile.';catch;end;quit;');