【问题标题】:How to merge two maps in parallel?如何并行合并两个地图?
【发布时间】:2021-01-04 05:32:59
【问题描述】:

我有两张大图,如下,

std::map<std::string, int> map1;
std::map<std::string, int> map2;

map2 可能有一些在 map1 中不存在的键。

那我想得到同一个key标注的值的总和,如下,

// merging to map1
for(auto it=map2.begin(); it!=map2.end(); it++)
    map1[it->first] += it->second;

我想并行化上述代码以提高其性能。

我该怎么办?

【问题讨论】:

  • 请注意,您的算法当前是O(n log m),而它可能是O(n + m)(代码类似于..std::merge)。

标签: c++ parallel-processing


【解决方案1】:

棘手的部分是并行迭代单个地图(只读)。如果您对密钥的分布有所了解,那就太好了。

同时编辑地图中的值(不是插入)是安全的。 添加元素不是。

要添加的元素可以是单独的映射(每个工作线程一个),然后合并到目标映射中,但从根本上来说,将 k 个键添加到一个大小的映射需要 O(klg(n+k)) 时间n;如果您记录每个节点的去向,您可以将其降低到 O(k)。但这是对整个容器的变异操作,所以不能并行进行。

(C++ 缺乏一种方法来保证可以在恒定时间内插入一系列顺序映射节点)。

但是,此成本仅适用于映射 2 中的键,而不适用于映射 1。这是一个很小的数字,您可以将映射 2 通过键拆分为多个大小相等的块,您的状态很好。

【讨论】:

    【解决方案2】:

    很明显,这些映射包含唯一的条目,如果一个线程只从“aa-jz”访问字符串,而一个线程从“ka-zz”访问字符串,那么就不会有同步问题——假设你不是为 map1 创建新条目。否则所有线程都需要写入本地地图。

    Map2 需要分成(几乎)大小相似的块,这可能很难实现。

    无论如何,无论并行度如何,最大的优化都应该来自搜索提示——因为 map2 或 map2 的块是按排序顺序处理的,因此可以简单地使用最后一个迭代器来 map1作为应该找到相应密钥的起点。

    EDITC++11/14/17/20 STL 确实只有插入提示,没有搜索提示。

    那么另一种选择是将映射序列化为向量并以 O(N+K) 的复杂度进行合并排序。

    【讨论】:

      【解决方案3】:

      不回答并行性,而是关于性能:

      您的算法是O(n log m),而常规合并算法是O(n + m)

      auto it1 = map1.begin();
      auto it2 = map2.begin();
      
      while (it2 != map2.end()) { // no need of it1 != map1.end()
          if (it1->first < it2->first) {
              ++it1;
          } else { // it1->first == it2->first as map1 has all keys
              it2->second += it1->second;
              ++it1;
              ++it2;
          }
      }
      

      注意:简化为 map1 的合并代码包含来自 map2 的所有键。

      【讨论】:

        猜你喜欢
        • 2012-02-06
        • 2023-03-16
        • 1970-01-01
        • 1970-01-01
        • 2017-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多