有没有办法在同一台计算机上的 MATLAB 进程之间共享内存?
我在多核计算机上运行多个 MATLAB 进程(运行 Windows,如果重要的话)。它们都使用相同的巨大输入数据。在内存中只有一个副本会很好。
编辑:不幸的是,每个进程都需要访问整个巨大的输入数据,因此没有办法分割数据并解决问题。
有没有办法在同一台计算机上的 MATLAB 进程之间共享内存?
我在多核计算机上运行多个 MATLAB 进程(运行 Windows,如果重要的话)。它们都使用相同的巨大输入数据。在内存中只有一个副本会很好。
编辑:不幸的是,每个进程都需要访问整个巨大的输入数据,因此没有办法分割数据并解决问题。
如果进程只读取数据但不修改它,那么我相信您可以将输入数据放入一个大文件中,并让每个进程打开并从该文件中读取。每个进程都有自己的文件位置指示器,它可以移动到文件中的任何位置来读取它需要的数据。我测试了两个 MATLAB 进程同时从一个文件中读取一百万次左右,一切似乎都运行良好。我只使用了基本的文件 I/O 命令(如下所列)。假设您拥有 MATLAB R2008a 或更高版本,您似乎也可以使用MEMMAPFILE来执行此操作,正如Fooz 先生在他的回答(以及评论中的 SCFrench )中提到的那样。
以下是您可能会为此使用的一些文件 I/O 命令:
FOPEN:每个进程都会调用 FOPEN 并返回一个文件标识符,它将在所有后续调用中使用。您可以以二进制或文本模式打开文件:
fid = fopen('data.dat','r'); % Binary mode
fid = fopen('data.txt','rt'); % Text mode
FREAD:在二进制模式下,FREAD 将从文件中读取数据:
A = fread(fid,20,'double'); % Reads 20 double-precision values
FSCANF:在文本模式下,FSCANF 将从文件中读取和格式化数据:
A = fscanf(fid,'%d',4); % Reads 4 integer values
FTELL:这将告诉您文件开头的当前文件位置指示符(以字节为单位):
ftell(fid)
ans =
8 % The position indicator is 8 bytes from the file beginning
FSEEK:这会将文件位置指示器设置到文件中的所需位置:
fseek(fid,0,-1); % Moves the position indicator to the file beginning
FCLOSE:每个进程都必须关闭对文件的访问(很容易忘记这样做):
fclose(fid);
该解决方案可能要求输入文件具有易于遍历的结构良好的格式(即只有一个大矩阵)。如果它有很多可变长度字段,那么从文件中的正确位置读取数据可能会变得非常棘手。
如果流程还必须修改数据,这可能会变得更加困难。通常,您不希望文件/内存位置同时被多个进程写入,或者被一个进程写入而另一个进程正在从同一位置读取,因为可能会导致不需要的行为。在这种情况下,您必须限制对文件的访问,以便一次只有一个进程在对其进行操作。其他进程必须等到第一个进程完成。在这种情况下,每个进程必须运行的示例代码版本是:
processDone = false;
while ~processDone,
if file_is_free(), % A function to check that other processes are not
% accessing the file
fid = fopen(fileName,'r+'); % Open the file
perform_process(fid); % The computation this process has to do
fclose(fid); % Close the file
processDone = true;
end
end
像这样的同步机制(“锁”)有时会产生很高的开销,从而降低代码的整体并行效率。
您可能想查看我的 Matlab 文件交换提交“sharedmatrix”#28572。它允许 Matlab 矩阵存在于共享内存中,前提是您使用的是某种 Unix 风格。然后可以将共享矩阵附加到 parfor 或 spmd 的主体中,即
shmkey=12345;
sharedmatrix('clone',shmkey,X);
clear X;
spmd(8)
X=sharedmatrix('attach',shmkey);
% do something with X
sharedmatrix('detach',shmkey,X);
end
sharedmatrix('free',shmkey);
由于 X 存在于 spmd(或 parfor)主体的共享内存中,因此它没有加载时间和通信时间。从 Matlab 的角度来看,它是 spmd(或 parfor)主体中新创建的变量。
干杯,
乔什
http://www.mathworks.com/matlabcentral/fileexchange/28572-sharedmatrix
编辑:将数据放入原始文件并使用memmapfile(感谢 SCFrench)。
============================================
不,没有真正的方法可以做到这一点。
我的前两个解决方案是:在数据中购买更多 RAM 或页面。
您可以做的最接近的事情是使用 mex 函数来分配共享内存,然后允许连续调用 mex 函数以提取较小的内存片。您不想将共享内存包装为 Matlab 数组(因为 Matlab 的内存模型不能很好地处理它)。
我打算建议调查 memmap,但显然这是有问题的。
有时您可以先运行一个 Matlab 程序来预处理或将数据拆分成更小的块。然后每个 Matlab 进程都可以在其自己的较小块上运行。
这是一个关于在 Matlab 中处理大型数据集的教程。
可能不会,至少不会像对待常规 MATLAB 变量那样对待数据。
如果在 Windows 机器上,您可以创建一个 COM/ActiveX 包装器来访问您的共享数据。MATLAB 允许通过该actxserver
函数使用 COM 对象。但是,您是否真的可以通过不同的流程“直接”访问数据,这是值得怀疑的。在 MATLAB 和 COM 之间有某种编组层,并且数据被转换,至少根据 Mathworks 文档在MATLAB 和 COM 之间交换数据。如果我必须在 Windows 机器上通过快速访问在进程之间共享结构化数据,我可能会用 C++ 编写一些东西来通过Boost::interprocess使用共享内存并将对它的访问包装在进程内 COM 服务器 (DLL) 中。我以前做过,一次。尽管 Boost::interprocess 让它变得容易得多,但它是一种痛苦。
Java 方法(因为 MATLAB 在 Java 之上运行)会更有希望,但据我所知,没有任何像样的 Java 库可以提供对共享内存的访问。最接近的可能是通过java.nio.MappedByteBuffer使用内存映射文件,但这确实是低级的。不过,如果您的数据是相对“方形”的形式(例如,大的 2-D 或 3-D 或 4-D 大小均匀的数据矩阵),这可能工作正常。
您可以尝试使用 HDF5 文件,MATLAB 具有内置的HDF5 支持,而且它“相对”快。但根据我的经验,HDF5 似乎不能很好地处理并发。(至少当一个进程正在写入而其他进程是读取器时不会。如果有多个读取器而没有写入器,它就可以正常工作。)