【问题标题】:Preallocating memory for variable that changes size every iteration (long text file)为每次迭代都会改变大小的变量预分配内存(长文本文件)
【发布时间】:2019-06-23 12:00:11
【问题描述】:

我编写了一个代码,可以将图像转换为用于光刻的文本文件。图片为高分辨率(26.5k x 26.5k),文本文件超过 2MB。我的问题是代码需要很长时间才能工作,我怀疑它与内存碎片有关(我不是经验丰富的程序员,特别是刚开始使用 MATLAB)。它在两个地方滞后:在您必须选择要使用的特定图像之前,以及在处理它之后。

在处理部分,我从 MATLAB 得到以下评论:

指示的变量或数组的大小似乎随着每次循环迭代而变化。通常,出现此消息是因为数组正在通过赋值或连接增长......

但是还有这部分:

如果满足以下任一条件,则可能适合禁止显示此消息,如调整代码分析器消息指示器和消息中所述: 循环代码包含数组增长的条件块。 (在这种情况下,仅当循环找到此类条件时才增长数组是合理的。) 对于循环中的每次迭代,连接的长度会有所不同(例如具有可变长度的字符向量)。进入循环前,数组的总大小是无法计算的。

输出文本文件很大程度上取决于提供的图像和其中的黑白像素数。

所以不知道有没有什么办法可以提高代码的性能呢?

在选择图片文件之前,几乎没有任何计算,携带的也很简单,不知道为什么这么慢。

对于第一个函数,就在调用打开图像文件的第二个函数之前:

function print_contacts(pixl, size, xRd, yRd, zRd, xRu, yRu, zRu)

meas_L=3960.05; % the lateral and veritcal measured distance e.g. 4900.5 between large pluses, 3960.05 between dots in corners
%%
conv=(size*1000)/pixl;%0.267;%0.4215; % pixel to microns
siz=pixl*conv;
xLd=0.0;
yLd=0.0;
zLd=0.0;

%%
delta_x_H=xLd-xRd;
delta_y_H=yLd-yRd;
delta_z_V=-(zLd-zRd);

delta_x_V=xRu-xRd;
delta_y_V=yRu-yRd;
delta_z_H=-(zRu-zRd);

%% find x-y angle of rotation teta (if teta is positive then rotation is clockwise)

if yRd > 0
    teta_xy=atand(-xRd/yRd)-90;
else
    teta_xy=atand(-xRd/yRd)+90;
end

%% find x-z angle of rotation teta (if teta is positive then rotation is clockwise)

teta_xz=atand(delta_z_H/delta_x_H);

%% find y-z angle of rotation teta (if teta is positive then rotation is clockwise)

teta_yz=atand(delta_z_V/delta_y_V);

%%
del_z_H=delta_z_H/meas_L*conv*pixl;
del_z_V=delta_z_V/meas_L*conv*pixl;

vec_xz=linspace(0,del_z_H,pixl);
vec_yz=linspace(0,del_z_V,pixl);
[X,Y] = meshgrid(vec_yz,vec_xz);
Z1=(X + Y);
shift=Z1(pixl/2,pixl/2);
valZ=round((Z1-shift),2);
%surf(valZ);
con=[conv];
R = [cosd(teta_xy) -sind(teta_xy); sind(teta_xy) cosd(teta_xy)];

PPM.Y=con;
PPM.X=con;

regionpropsApply(PPM, valZ, siz, R, conv)

之后是函数regionpropsApply,它允许您选择图像文件并将其分割成单独的图像,每个图像将由第三个也是最后一个函数处理成一个文本文件,其中我有这个命令收集将进入文本文件的长字符串:

str2File = [str2File;cmdJump;cmdZ;cmdMov];

其中cmdJump、cmdZ 和cmdMov 是在此特定迭代中创建的命令。在迭代之前,我已经知道所需的迭代次数。每次迭代都将始终包含这 3 个命令。每个图像(从原始图像中分割出来的)都被单独处理。我应该何时以及如何预分配内存?

目前,执行代码需要 40 多分钟,考虑到输出文件只有 2MB 的事实,我真的希望不到几分钟。

【问题讨论】:

  • 你分析过代码吗?它会告诉你所有时间都花在了哪里。 mathworks.com/help/matlab/ref/profile.html
  • 我不知道这是可能的,由于其他方法没有多大作用,很遗憾,我会尝试一下。谢谢!

标签: arrays image matlab memory-management pre-allocation


【解决方案1】:

在您的第一段代码中,我认为这是缓慢的部分:

vec_xz=linspace(0,del_z_H,pixl);
vec_yz=linspace(0,del_z_V,pixl);
[X,Y] = meshgrid(vec_yz,vec_xz);
Z1=(X + Y);
shift=Z1(pixl/2,pixl/2);
valZ=round((Z1-shift),2);

由于您正在处理非常大的图像,我认为pixl 这是一个很大的数字。您生成 4 个图像大小的矩阵。但是其中 3 个包含中间数据,仅在上面的代码中使用。不要将每个计算结果分配给一个新变量,而是重用变量以避免使用过多的内存。例如,使用x = func(x) 调用函数允许函数就地工作,修改x 而不是复制它。现在你不应该再让Z1 占用内存。

图片X 和Y 完全是多余的。从 R2016b 开始,您可以简单地添加两个正交向量,并且在此之前的 10 年中,我们有 bsxfun 用于这种类型的操作。这不仅可以节省内存,还可以通过更好地使用缓存来加快计算速度。

因此,您可以通过以下方式执行与上述相同的操作:

vec_xz = linspace(0, del_z_H, pixl);
vec_yz = linspace(0, del_z_V, pixl);
valZ = vec_xz + vec_yz.';
shift = valZ(pixl/2, pixl/2);
valZ = round(valZ-shift, 2);

如果您有旧版本的 MATLAB,请将第 3 行替换为:

valZ = bsxfun(@plus, vec_xz, vec_yz.');

最后,我们可以通过改变它们的顺序来减少操作的数量:我们不是从每个像素中减去shift,而是从两个向量中的每一个中减去一部分:

vec_xz = linspace(0, del_z_H, pixl);
vec_xz = vec_xz - vec_xz(pixl/2);
vec_yz = linspace(0, del_z_V, pixl);
vec_yz = vec_yz - vec_yz(pixl/2);
valZ = vec_xz + vec_yz.';
valZ = round(valZ, 2);

至于你问题的第二部分,我不知道那里还有什么以及你对你构建的字符串做了什么,但如果你所做的只是构建这个长字符串然后将它写入文件,你应该在你去的时候把它写到文件中:

file = fopen('name.txt', 'wt');
for ...
   fwrite(file, [cmdJump;cmdZ;cmdMov];
end
fclose(file);

如果您需要在写入之前以某种方式修改字符串,您可以将它们存储在一个元胞数组中,您可以预先分配它,因为您知道循环的迭代次数:

str2File = cell(N,1);
for ii=1:N
   str2File{ii} = [cmdJump;cmdZ;cmdMov];
end

【讨论】:

  • 非常感谢您的回答。哪个选项应该更快?每次迭代都写入文件(有很多,但不超过几万个),或者预先分配一个单元格数组,然后我将其更改为字符串并写入文件?在写入文件之前,我必须将元胞数组转换为一个字符串,对吗?
  • 我应该补充一点,原始片段的每个片段都在第一个片段之后附加了 txt 文件。 (在第三个功能中)。我可以添加整个代码,但我认为这里可能会很乱。
  • @FourierLeibniz:最好的办法是尝试两种方法并为它们计时。有时很难预测什么会更快。原则上直接写入磁盘更简单、更快,但 MATLAB 会增加难以预测的开销,并且会随着解释器的改进而随更新而变化。
猜你喜欢
  • 2014-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 2019-12-13
相关资源
最近更新 更多