Matlab中的多CPU并行计算:一种基于Matlab引擎的混合编程
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Matlab中的多CPU并行计算:一种基于Matlab引擎的混合编程
实验室新购置了一台双核本本,就忍不住琢磨一下,好使得我那Matlab下的程序更有效率。然而Google下来却收获甚微,有朋友提到可以使用Matlab的Distribution Computing Toolbox,但似乎是用于多台电脑联网时的情况,与我的要求相差甚远。因此只好自己鼓捣一下,借此机会抛砖引玉,欢迎大家共同探讨。
方法思路非常清晰:使用C和Matlab混合编程的方法,在C中用线程启动Matlab引擎,如此就可以启动多个程序,充分发挥多核CPU的优势。
在这里给出一个简单的示例程序,其线程任务为通过随机数方法来计算pi(就是为了拖时间)。
示例一共由4个文件构成:
ThreadDemo.cpp: 主程序
compopts.bat: 编译配置文件
Thread1.m: 计算pi的程序
disp2.m: 辅助显示程序
只需在Matlab环境下调用mbuild -f compopts.bat -v ThreadDemo.cpp命令即可生成可执行文件ThreadDemo.exe,再输入命令!ThreadDemo即可观察结果。实验环境为在Matlab6.5, VC6.0。Matlab7.0由于对混合编程的方式进行了较大改动,示例可以通过编译,但不能正常运行。
以下为运行结果:
>> !ThreadDemo
10:41:32 --> Time used: 27", 10:41:05 -- 10:41:32
10:41:32 --> Task1: IterNum = 100000000, Result = 3.141961
10:41:33 --> Time used: 27", 10:41:06 -- 10:41:33
10:41:33 --> Task2: IterNum = 100000000, Result = 3.141961
可以看到两个任务几乎同时启动,同时结束。运行时可以看到打开了两个独立的Matlab引擎(随后被隐藏),CPU占用率100%,共耗时28s。如果单独运行两个任务,则分别需要25s。考虑到引擎启动及数据传输的时间,这个结果还是比较合理的。
随后附上各文件,也可从附件直接下载。由于代码较为简单,就不多做解释了,大家看看就明白了。
上文给出的是使用mbuild生成独立程序的方法,类似的我们也可以使用mex来生成Matlab中调用的dll,也有相同效果。
-----------------------------------------------------------------------------------
ThreadDemo.cpp
/**********************************************************
run the following command to generate executable file
>> mbuild -f compopts.bat -v ThreadDemo.cpp
**********************************************************/
#include
#include
#include
#include
#include
#include "engine.h"
#include "matlab.hpp"
typedef enum{
MAT_TASK1,
MAT_TASK2
} EMatTask;
const int BUF_SIZE = 1024;
bool bTask1 = 0;
bool bTask2 = 0;
void MatTask(void *pTaskID)
{
const double IterNum1 = 10e7;
const double IterNum2 = 10e7;
char strInfoBuf[BUF_SIZE];
EMa
tTask TaskID;
Engine *ep;
mxArray *T = NULL;
if (!(ep = engOpenSingleUse("\0", NULL, NULL))) {
fprintf(stderr, "\nCan't start MATLAB engine\n");
return;
}
engSetVisible(ep, 0);
engOutputBuffer(ep, strInfoBuf, BUF_SIZE);
engEvalString(ep, "cd E:\\Work\\Program\\Matlab\\Test\\TestThread");
TaskID = *((EMatTask *)pTaskID);
if(TaskID == MAT_TASK1)
{
T = mxCreateDoubleMatrix(1, 1, mxREAL);
memcpy((void *)mxGetPr(T), (void *)(&IterNum1), sizeof(double));
engPutVariable(ep, "T", T);
engEvalString(ep, "y = Thread1(T);");
printf("%s", strInfoBuf);
engEvalString(ep, "disp2(sprintf('Task1: IterNum = %d, Result = %f', T, y));");
printf("%s", strInfoBuf);
bTask1 = 1;
}
else if(TaskID == MAT_TASK2)
{
T = mxCreateDoubleMatrix(1, 1, mxREAL);
memcpy((void *)mxGetPr(T), (void *)(&IterNum2), sizeof(double));
engPutVariable(ep, "T", T);
engEvalString(ep, "y = Thread1(T);");
printf("%s", strInfoBuf);
engEvalString(ep, "disp2(sprintf('Task2: IterNum = %d, Result = %f', T, y));");
printf("%s", strInfoBuf);
bTask2 = 1;
}
// engEvalString(ep, "whos");
// printf("%s", strInfoBuf);
engClose(ep);
}
void main()
{
EMatTask TaskID1, TaskID2;
bool bThreadMode = 1;
TaskID1 = MAT_TASK1;
TaskID2 = MAT_TASK2;
if(!bThreadMode)
{
MatTask((void *)&TaskID1);
MatTask((void *)&TaskID2);
}
else
{
_beginthread( MatTask, 0, (void *)&TaskID1 );
_beginthread( MatTask, 0, (void *)&TaskID2 );
while(!(bTask1 & bTask2))
{
Sleep(100);
}
}
}
----------------------------------------------------------------------------------
compopts.bat
@echo off
rem MSVC60COMPP.BAT
rem
rem Compile and link options used for building MATLAB compiler programs
rem with Microsoft Visual C++ compiler version 6.0
rem
rem $Revision: 1.18 $ $Date: 2002/03/29 16:30:16 $
rem
rem ********************************************************************
rem General parameters
rem ********************************************************************
set MATLAB=%MATLAB%
set MSVCDir=D:\Program Files\Microsoft Visual Studio\VC98
set MSDevDir=%MSVCDir%\..\Common\msdev98
set PATH=%MSVCDir%\BIN;%MSDevDir%\bin;%MATLAB_BIN%;%PATH%
set INCLUDE=%MSVCDir%\INCLUDE;%MSVCDir%\MFC\INCLUDE;%MSVCDir%\ATL\INCLUDE;%INCLUDE%
set LIB=%MSVCDir%\LIB;%MSVCDir%\MFC\LIB;%LIB%
set PERL="%MATLAB%\sys\perl\win32\bin\perl.exe"
rem ********************************************************************
rem Compiler parameters
rem ********************************************************************
set COMPILER=cl
set OPTIMFLAGS=-O2 -DNDEBUG
set DEBUGFLAGS=-Zi -Fd"%OUTDIR%%MEX_NAME%.pdb"
set CPPOPTIMFLAGS=-O2 -DNDEBUG
set CPPDEBUGFLAGS=-Zi -Fd"%OUTDIR%%MEX_NAME%.pdb"
set COMPFLAGS=-c -MT -D"_X86_" -Zp8 -G5 -W3 -nologo
set CPPCOMPFLAGS=-c -Zp8 -G5 -W3 -nologo -Zm500 -GX -MD -I"%MATLAB%\extern\include\cpp" -DMSVC -DIBMPC -DMSWIND
set DLLCOMPFLAGS=-c -Zp8 -G5 -W3 -nologo -DMSVC -DIBMPC -DMSWIND
set NAME_OBJECT=/Fo
rem ********************************************************************
rem Library creation commands creating import and export libraries
rem ********************************************************************
set DLL_MAKEDEF=type %BASE_EXPORTS_FILE% | %PERL% -e "print \"LIBRARY %MEX_NAME%.dll\nEXPORTS\n\"; while (<>) {print;}" > %DEF_FILE%
rem ********************************************************************
rem Linker parameters
rem MATLAB_EXTLIB is set automatically by mex.bat
rem ********************************************************************
set LIBLOC=%MATLAB%\extern\lib\win32\microsoft\msvc60
set LINKER=link
set LINKFLAGS=kernel32.lib user32.lib gdi32.lib advapi32.lib oleaut32.lib ole32.lib /LIBPATH:"%LIBLOC%" libmmfile.lib libmatlb.lib libeng.lib /nologo
set LINKFLAGS=%LINKFLAGS% libmx.lib libmat.lib libmwservices.lib libmex.lib libut.lib
set CPPLINKFLAGS=%MATLAB_EXTLIB%\libmatpm.lib
set DLLLINKFLAGS= %LINKFLAGS% /dll /implib:"%OUTDIR%%MEX_NAME%.lib" /def:%DEF_FILE%
set HGLINKFLAGS=sgl.lib libmwsglm.lib
set LINKOPTIMFLAGS=
set LINKDEBUGFLAGS=/debug
set LINK_FILE=
set LINK_LIB=
set NAME_OUTPUT="/out:%OUTDIR%%MEX_NAME%.exe"
set DLL_NAME_OUTPUT="/out:%OUTDIR%%MEX_NAME%.dll"
set RSP_FILE_INDICATOR=@
rem ********************************************************************
rem Resource compiler parameters
rem ********************************************************************
set RC_COMPILER=rc /fo "%OUTDIR%%RES_NAME%.res"
set RC_LINKER=
rem ********************************************************************
rem IDL Compiler
rem ********************************************************************
set IDL_COMPILER=midl /nologo /win32 /I "%MATLAB%\extern\include"
set IDL_OUTPUTDIR= /out "%OUTDIRN%"
set IDL_DEBUG_FLAGS= /D "_DEBUG"
set IDL_OPTIM_FLAGS= /D "NDEBUG"
set POSTLINK_CMDS1=if exist %LIB_NAME%.def del %LIB_NAME%.def
----------------------------------------------------------------------------------
Thread1.m
function p = Thread1(N)
t1 = clock;
strT1 = datestr(now,'HH:MM:SS');
count = 0;
for k = 1:N
x = 2 * rand - 1;
y = 2 * rand - 1;
if(sqrt(x^2 + y^2) <= 1)
count = count + 1;
end;
en
d;
p = 4.0 * count / N;
t2 = clock;
strT2 = datestr(now,'HH:MM:SS');
t = etime(t2,t1);
mins = floor(t / 60);
secs = round(mod(t,60));
if(mins == 0)
disp2(sprintf('Time used: %d", %s -- %s',secs,strT1,strT2));
else
disp2(sprintf('Time used: %d''%d"(%.3fs), %s -- %s',mins,secs,t, strT1,strT2));
end;
----------------------------------------------------------------------------------
disp2.m
function disp2(str, DispMask, CurrMask)
if( (~exist('DispMask')) & (~exist('CurrMask')) )
disp(strcat(datestr(now,'HH:MM:SS'), ' -->', sprintf(' %s', str)));
return;
end;
if(bitand(DispMask, CurrMask))
disp(strcat(datestr(now,'HH:MM:SS'), ' -->', sprintf(' %s', str)));
end;
----------------------------------------------------------------------------------