2

我目前有执行以下操作的 Matlab 代码:

map = collections.Map;
for i = 1:N
    key = getKey(i);
    if isKey(map, key)
        % Return the value stored at key.
    else
        % Calculate a new value, store it in the map using key.
    end
end

这个循环需要很长时间才能运行,我想使用 parfor 来帮助提高效率。但是,我似乎无法为 parfor 循环内的地图分配值。关于我能做什么的任何想法?collections.Map 的使用并不牢固,我愿意接受并行记忆的替代建议,只要它们快速高效(并且线程安全,我意识到 Map 可能不是)。

从下面的评论中添加:我希望有更多的线程安全方式在循环期间向映射添加新值,以便任何后续循环都可以使用预先计算的值。计算在时间上是相当昂贵的。

4

2 回答 2

1

“线程安全”在这里是错误的关注点。一般来说,“线程安全”不适用于 Matlab 对象,因为 Matlab 在 M 代码级别是单线程的。每个 Matlab 实例/进程只有一个 Matlab 解释器线程。并行parfor迭代发生在单独的进程甚至单独的机器上,而不是单独的线程上,所以这将是一个进程间通信问题而不是多线程。parfor并且您不能通过分配在工作循环传递的状态与彼此或封闭工作空间之间进行双向“通信” ;我很确定数据传输只发生在循环开始和循环结束。

如果你真的想在 a中进行记忆parfor,你需要某种客户端-服务器记忆机制。您需要做的是在所有 Matlab 池工作人员都可以看到但在 M 代码中涉及的 Matlab 工作区外部的服务器上的进程中设置您的记忆缓存,并在循环内使用客户端代理对象通过某种进程间通信(如 RMI 或套接字调用)来查询缓存。主“服务器”缓存对象甚至可以在运行代码的主 Matlab 进程中parfor只要它是不受 M 代码解释器管理的 Java 或 C 结构,就可以循环。缓存的服务器端将处理安全的并发访问(可能使用线程安全映射和多个工作线程,可能通过序列化请求)。客户端可以有一个本地状态代理,只要它不是基于 M 代码索引来更新其元素。

更一般地说,如果你想在工作人员之间进行交互parfor,你需要一个共享的数据存储,比如他们都可以访问的数据库或文件系统。

也许你可以只设置一个小memcached实例,或者一个轻量级的内存数据库(也许是 JDK 附带的 Derby?),并将其用作服务器端缓存,在所有工作人员中创建数据库句柄来访问它。或者也许有一组更轻量级的 Java 对象,它们为 a ConcurrentMapor提供了一个瘦 RMI 接口synchronized Map?您还可以使用 Matlab 对象创建一个缓存服务器,例如containers.Map让一个单独的 Matlab 进程充当缓存服务器,在套接字上侦听请求并对其进行序列化,并让parfor工作人员通过客户端代理对象get()set()使用的方法访问它IPC 调用缓存服务器进程来完成它们的工作。

这一切都可能是一个很大的开销,所以只有当计算真的很昂贵时才值得。

于 2013-08-09T02:10:18.467 回答
0

显然你指的是containers.map。我会使用临时数组/单元格数组来存储 的乘积parfor并在循环之后分配所有新内容。

% original map
keySet = {'a','b','c','f'};
map = containers.Map(keySet, 1:length(keySet));

% simulates your keys/generated values 
getKey = {'f','g','h'};
getVal = (5:7);

% Parfor body
parfor i = 1:3
    key = getKey{i};
    if isKey(map, key)
        % Return the value stored at key.
        map(key);
    else
        % Calculate a new value, store it in a temp array/cell-array 
        keyNew{i} = key;
        valNew(i) = getVal(i);
    end
end

% assign to map the new pairs of keys/values
indNew = ~cellfun(@isempty, keyNew); % clean up empty cells
newMap = containers.Map(keyNew(indNew), valNew(indNew));
map = [map; newMap];

编辑:您不能使用parfor和动态地使值可用于后续迭代,仅仅是因为没有像循环这样的subsequent iterations东西parfor

parfor文档中:

注意:由于迭代顺序的独立性,parfor 的执行不能保证确定的结果。

这意味着(正如这个SO问题/答案很好地强调的那样),并行执行的迭代是 AND 必须被认为是独立的,而不是常规的 for 循环。结果,它们的执行/完成顺序是不可预测的,并且它们对其他迭代输出的访问/依赖是不可行的。

于 2013-08-08T18:42:13.290 回答