【问题标题】:Using SPMD to run a series of jobs while updating a common variable使用 SPMD 运行一系列作业,同时更新一个公共变量
【发布时间】:2014-02-10 02:17:47
【问题描述】:

我目前正在尝试使用 MATLAB 2013b 并行运行非常耗时的实验。

加快速度的一种策略是使用一个实验的结果来“热启动”下一个实验。就我而言,这有点复杂,因为每个实验都有n_types 类型之一,而我只能使用k 类型的实验来加速另一个k 类型的实验。

不幸的是,我无法使用parfor 函数实现此策略,因为它需要每个作业更新一个公共变量(存储热启动信息)。也就是说,我听说可以使用spmd 框架来做到这一点。

我想知道是否有人可以帮助我将以下通用(非工作)parfor 代码块“翻译”成可以在spmd 代码中工作的内容。

n_cores = %provided by user (# of workers that are available)
inputs  = %provided by user (n_jobs x 1 cell array of structs)
types   = %provided by user (n_types x 1 array of integer values)
n_jobs  = length(inputs)
n_types = length(unique(types))

outputs     = cell(n_jobs,1) %cell array to store job output
warm_starts = cell(0,n_types) %empty 0 x n_type cell array to store warm start data

matlabpool('open',n_cores)

parfor i = 1:length(jobs)

   %run myfun in parallel
   outputs{i} = myfun(inputs{i},warm_starts(types(i)));

   %update warm start data for experiments of this type with data from current experiment
   warm_starts{end+1,types(i)) = get_warm_start(job_outputs{i});

end

【问题讨论】:

    标签: matlab parallel-processing


    【解决方案1】:

    我不太清楚您可能希望为每个type 存储多少个不同的warm_starts。我假设您只想存储 1 个。您可以这样做:

    jobs  = rand(1,97); % note prime number of jobs
    types = randi([1, 5], size(jobs));
    n_jobs = numel(jobs);
    n_types = numel(unique(types));
    warm_starts = cell(1, n_types);
    
    spmd
        jobs_per_lab = ceil(n_jobs / numlabs);
        outputs = cell(jobs_per_lab, 1);
        for idx = 1:jobs_per_lab
            job_idx = idx + ((labindex-1)*jobs_per_lab);
            if job_idx > n_jobs
                % Off the end of 'jobs', no work to do
                this_warm_start = NaN;
                this_type       = NaN;
            else
                this_type = types(job_idx);
                if ~isempty(warm_starts{this_type})
                    this_warm_start = warm_starts{this_type};
                else
                    this_warm_start = 0;
                end
                outputs{idx} = this_warm_start + types(job_idx) * jobs(job_idx); % some function goes here
                this_warm_start = rand();
            end
            % All-to-all communication to exchange 'this_warm_start' values.
            % After this, each worker has a 2 x numlabs cell array of warm starts and types
            all_warm_starts_this_round = gcat({this_type; this_warm_start}, 2);
            for w = 1:numlabs
                warm_start_type = all_warm_starts_this_round{1, w};
                warm_start_value = all_warm_starts_this_round{2, w};
                if ~isnan(warm_start_type)
                    warm_starts{warm_start_type} = warm_start_value;
                end
            end
        end
        % Finally, collect all results on lab 1
        outputs = gcat(outputs, 1, 1);
    end
    % Dereference the Composite
    outputs = outputs{1};
    

    我在那里做的主要事情是手动拆分工作,以便每个工作人员操作一大块“工作”,然后在每轮结束后使用GCAT 广播热启动信息。

    【讨论】:

    • 谢谢!可以肯定的是:除非 n_jobs 是 numlabs 的倍数,否则这段代码不会出错吗?在这种情况下,在我看来,您会引用不存在的类型/工作。
    • 嘎。如果作业的数量不是 numlabs 的倍数,那么肯定会出现不小的错误。在这种情况下,一些工作人员提前完成,对剩余的 mod(n_jobs,numlabs) 工作人员的“gcat”调用返回以下错误:“使用 labReceive 时出错。遇到通信不匹配错误:另一个实验室在实验室接收。”
    • 是的,对 GCAT 的调用是集体的,因此您必须确保它们是一起调用的。我更新了示例代码以展示如何处理 n_jobs 不是 numlabs 的倍数的情况。
    • 谢谢!了解 GCAT 工作原理的最后一个问题:假设工人 1 仍在运行实验功能,但工人 2 已完成并到达 GCAT 调用。工人 2 会执行调用吗?还是必须等到工人 1 也到达 GCAT?
    • GCAT 是集体的 all-to-all 通信 - 因此工人 2 不能离开 GCAT,直到工人 1 至少进入 GCAT。如果您的实验花费不同的时间,这可能会导致您的员工闲着等待其他人。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-22
    • 2017-05-06
    • 2023-04-01
    • 2011-01-16
    • 2018-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多