在Matlab中使用parfor循环内部的映射

在Matlab中使用parfor循环内部的映射,matlab,parallel-processing,memoization,Matlab,Parallel Processing,Memoization,我目前有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 这个循环需要很长时间才能运行,我想使用pa

我目前有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可能不是)


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

显然你指的是。我将使用临时数组/单元数组来存储
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
并动态地将值提供给后续迭代,因为在
parfor
循环中不存在
后续迭代

从文件中:

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

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

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

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

更一般地说,如果您希望在
parfor
过程中工作人员之间进行交互,那么您需要一个共享数据存储,比如数据库或文件系统之类的东西,他们都可以访问

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


这可能会带来很大的开销,因此只有在计算非常昂贵的情况下才有价值。

您的键是什么类型的数据?我使用的是字符串。更具体地说,我在一个键数组上使用mat2str的结果。我希望有更多线程安全的方法在循环期间向映射添加新值,以便任何后续循环都可以使用预先计算的值。计算在时间上是相当昂贵的。我认为你不能用
parfor
这样做,因为迭代是/必须被认为是独立的(因此它们的执行顺序、访问和依赖于其他迭代的输出)。实际上,也请参见此处的相关答案,仔细阅读其他答案;我认为这是无意中展示了OP想要的那种共享状态的副作用。它正在调用
randn
,这将提升全局
rng
状态,因此每个循环过程都直接依赖于先前循环过程中存储的值。它实现了OP正在寻找的缓存逻辑的本地版本。您可以将其作为指导—如果将缓存逻辑塞进函数中,您可以绕过一些语法限制。(具体来说,我认为
rng
的状态隐藏在Java对象中。)