【问题标题】:why inserting into set with same amount has different runtimes based on different approaches?为什么根据不同的方法插入相同数量的集合具有不同的运行时间?
【发布时间】:2019-09-02 06:04:10
【问题描述】:

我正在编写一个将组合生成为布尔向量形式的并行程序。由于组合是使用线程生成的,因此我会在每个线程完成其工作时将它们组合起来。

set<vector<bool>> Ci[T.size()];
//generate combinations in parallel and thread i add result in Ci[i]

start_time = omp_get_wtime();
set<vector<bool>> C;
for(int i=0;i<T.size();i++){
    cout << "i=" << i << "\t" << Ci[i].size() << endl;
    C.insert(Ci[i].begin(),Ci[i].end());//here combine them into a single set
}
end_time = omp_get_wtime();
total_time = end_time - start_time;
cout << " Total time:" <<total_time << endl;
cout <<  C.size();

线程总数,T.size() 会有所不同,但总组合(C 的大小)始终相同。 例如,

Enter threads:10
i=0 1
i=1 144
i=2 4320
i=3 47040
i=4 229320
i=5 550368
i=6 672672
i=7 411840
i=8 115830
i=9 11440
Total time:36.641s
C's size :2042975

Enter threads:128
i=0 9
i=1 45
i=2 165
...
i=120   10
i=121   11
i=122   12
i=123   13
i=124   14
i=125   15
i=126   16
i=127   18
Total time:6.432s
C's size :2042975

我不明白的是在这两种情况下,我在 C 中插入了相同数量的组合。为什么花费的时间不一样?

【问题讨论】:

  • 大小不一样...当我从0...9 运行时似乎还有很多工作虽然最后的大小是相同的,所以也许插入更小的块更快.也许this 可以帮忙?
  • 大小相同...我只是省略了从 i=3 到 i=119 的值。例如,当 i=12 203490 时,i=15 477445。只是这些值分布不均。
  • 我也是这么想的。因此,我使用不同的 C 大小和线程数进行测试。如果线程数为 126,则 C 大小为 53130 -> 总时间为 0.667 秒。如果线程数为 80 -> 总时间为 0.148 秒。在这种情况下,情况正好相反。
  • 您正在插入很多已经按顺序排列的元素。也许它会触发一些边缘情况,因为底层结构(RB-tree)需要做更多的工作来保持树的平衡。如果您的线程较少,那么已经有序的元素数量会更多,这就是您获得较低性能的原因。这只是猜测,但对我来说似乎是一个明智的解释。只是为了好玩,您可以尝试先将所有元素放入一个向量中,然后将其洗牌,然后将其放入集合中。
  • @nielsen 这可能是因为这些元素之间的分布方式不同。如果你想测试,ideone.com/TRWvuk -> 对于这个程序,输入 is(25 9 10) 这意味着从 25 个对象中选择 9 个对象并在 10 个线程上运行。合并结果发生在第 44 到 49 行。ideone.com/RT4ROR -> 对于这个程序,输入是(25 9 128),这意味着从 25 个对象中选择 9 个对象并在 128 个线程上运行。合并结果发生在第 79 到 85 行。

标签: c++ data-structures insert set


【解决方案1】:

我们没有看到所有必要的信息,但我怀疑问题是由集合大小的不均匀分布引起的。插入的复杂度为 O(n log(m + n)),其中 n 是插入 (C) 和 m 是要插入的集合的大小 (Ci[i])。

现在,考虑两个集合共有 2^24 个元素。

案例 1:n=2^16m=2^24-2^16

这里“大O”里面的项变成2^16 * log(2^24-2^16+2^16),也就是2^16* 24.

案例 2:n=2^23m=2^23

这里,同一个词是2^23*24,是案例1的2^7。 p>

我的观点是,如果你“合并”两个具有元素总数相同的集合,运行时间可能很大程度上取决于这些元素在它们之间的分布方式。

在您的第一个案例(10 个线程)中,集合大小的分布似乎更像案例 2(其中大多数具有相对较多的元素)。我们没有看到您的第二种情况(128 个线程)的完整数据,但集合大小似乎分布更加不均匀,因为显示的只有很少的元素。 (请注意,它可能表明您的并行计算负载平衡不佳。

【讨论】:

  • 你是对的,尤其是“如果你合并两个元素总数相同的集合,运行时间可能很大程度上取决于这些元素是如何分布在它们之间的。”
  • @Daniel Langr:抱歉,我在写评论时有一个误解——我已将其删除以避免将来造成混淆。但是,您的计算存在一个问题,即它考虑将大集合插入现有集合(案例 1)与将小集合插入现有集合(案例 2)。显然,插入小集合更便宜。继续...
  • 一个更合理的比较是考虑将两个组合在一起的具有相同大小的集合插入到现有集合中。如果现有集合为空(与结论无关),则案例 1(大小 2^24-2^16 和大小 2^16)将给出大约 (2^24-2^16)*24+2 ^16*24 = 2^24*24。案例 2(大小 2^23 和 2^23)将给出大约 2^23*23+2^23*24。 IE。大致相同。
  • @nilsen 我不认为我们可以在这里评估比较的合理性,因为我们不详细了解 OP 的数据。我只是想指出一个可能的原因。通常,即使您“合并”两组完全相同的大小,运行时间也可能会因实际数据而有很大差异。一些说明性(极端情况)实验在这里:quick-bench.com/aqcxm42XPw16O2VL93NEvLKoWAk.
  • @Daniel Langr 当我读到它时,OP 从一个空集 C 开始,并在其中插入了两组不同的集合。这两组集合的共同点是它们的组合大小相同。我要说的是,您的答案解决了通过将一组合并到另一组来组合(仅)两组的不同情况。在这种情况下,如果第二组比第一组大 2^7 倍,那么运行时间也是如此,这并不奇怪。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-27
  • 2016-02-08
  • 2013-05-19
  • 2015-07-31
  • 2018-03-24
  • 2016-07-19
  • 1970-01-01
相关资源
最近更新 更多