如何在MATLAB中实现进程间共享内存?

6

有没有办法在同一台计算机上的MATLAB进程之间共享内存?

我在多核计算机上运行几个MATLAB进程(如果有影响,运行Windows)。它们都使用相同的巨大输入数据。只在内存中保留一个副本会很好。

编辑:不幸的是,每个进程都需要访问整个巨大的输入数据,因此无法分割数据并解决问题。


1
我的数据可能很大,但是静态的,也就是说,函数不会改变它。是的,读取文件实际上可以解决这个问题。 - AnnaR
4个回答

6
如果进程仅仅是读取数据,而不修改数据,那么您可以将输入数据放入一个大文件中,并让每个进程打开并从该文件中读取。每个进程都有自己的文件位置指示器,它可以移动到任何位置以读取所需的数据。我测试了两个MATLAB进程同时从文件中读取一百万次左右,一切似乎都很正常。我只使用了基本的文件I/O命令(如下所列)。似乎您也可以使用MEMMAPFILE来完成这个任务,正如Mr Fooz在他的答案中提到的(SCFrench在评论中也提到过),假设您使用的是MATLAB R2008a或更新版本。
这里是您可能会用到的一些文件I/O命令:
  • FOPEN: Each process will call FOPEN and return a file identifier it will use in all subsequent calls. You can open a file in either binary or text mode:

    fid = fopen('data.dat','r');   % Binary mode
    fid = fopen('data.txt','rt');  % Text mode
    
  • FREAD: In binary mode, FREAD will read data from the file:

    A = fread(fid,20,'double');  % Reads 20 double-precision values
    
  • FSCANF: In text mode, FSCANF will read and format data from the file:

    A = fscanf(fid,'%d',4);  % Reads 4 integer values
    
  • FGETL/FGETS: In text mode, these will read whole lines from the file.

  • FTELL: This will tell you the current file position indicator in bytes from the beginning of the file:

    ftell(fid)
    ans =
         8    % The position indicator is 8 bytes from the file beginning
    
  • FSEEK: This will set the file position indicator to a desired position in the file:

    fseek(fid,0,-1);  % Moves the position indicator to the file beginning
    
  • FCLOSE: Each process will have to close its access to the file (it's easy to forget to do this):

    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

像这样的同步机制(“”)有时会产生很高的开销,从而降低代码的整体并行效率。


哇!我会试试这个。这可能会解决我的问题。 - AnnaR

5
你可能想要查看我在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


4

编辑:将数据放入原始文件中,使用memmapfile(感谢SCFrench)。

============================================

没有真正的方法来解决这个问题。我的两个解决方案是:购买更多的RAM或将数据分页。最接近的方法是使用mex函数来分配共享内存,然后允许连续调用mex函数来提取更小的内存片段。您不希望将共享内存包装为Matlab数组(因为Matlab的内存模型无法很好地处理它)。我原本想建议看一下memmap,但显然存在问题。有时,您可以先运行一个Matlab程序来预处理或拆分数据成较小的块。然后每个Matlab进程都可以在自己的较小块上运行。这里有一个关于在Matlab中处理大型数据集的教程。

不是我想要的答案——我希望是“可以的,做这个”,但非常感谢提供链接,我现在就去读它。 - AnnaR
我再仔细查找了一下,也许这个链接可以解决问题:http://polaris.cs.uiuc.edu/matmarks/ - Mr Fooz
1
我已经在上面链接到“comp.soft-sys.matlab”新闻主题的更新中发布了一个单词“有问题”的更新。事实证明,这是早期MATLAB版本中的错误,并且在R2008a版本中得到了修复。 - SCFrench

1

可能不行,至少不能像处理常规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使用内存映射文件,但那真的很低级。不过,如果您的数据相对“方形”(例如大型二维、三维或四维同质大小数据矩阵),这可能还可以。

您可以尝试使用HDF5文件,MATLAB内置HDF5支持,并且速度“相对”较快。但根据我的经验,HDF5似乎与并发性不太兼容。(至少当一个进程正在写入而其他进程正在读取时不兼容。如果有多个读者而没有写者,则可以正常工作。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接