【问题标题】:Check if value exists across 16 containers检查值是否存在于 16 个容器中
【发布时间】:2012-05-23 05:51:40
【问题描述】:

我有 16 个线程来计算密钥的哈希值。我试图在线程之间分配工作,因为计算哈希并检查它是否以线性方式存在只使用了我 cpu 功率的一小部分。目前,我正在使用一个所有线程都可以使用互斥锁访问的地图容器。然而,由于实际的散列几乎不需要任何时间,线程大多处于空闲状态,等待另一个线程完成其业务,使用 map::count 检查键是否存在于映射中。

这个程序的主要目标是蛮力检查碰撞,因为在我将它添加到我的项目之前,我需要确保没有碰撞。

有没有办法使用单独的映射或其他容器来确定所述键是否存在,而不是在所有线程完成后使用每个键线性搜索每个映射?某种排队系统呢?

编辑:这是我试图线程化的函数:

int coll = 0;
map<long, bool> mymap;
string temp;
long myhash;
for (int i = 0; i < 256; i++)
  for (int j = 0; j < 256; j++)
    for (int k = 0; k < 256; k++)
    {
      temp = i;
      temp += j;
      temp += k;
      temp += temp;
      myhash = hash(temp.c_str());

      if (mymap.count(myhash))
      {
        coll++;
        cout << "Collision at " << i << " " << j << " " << k << endl;
      }
      else
      {
        mymap[myhash] = true;
      }
  }

cout << "Number of collisions: " << coll << endl;
cout << "Map size: " << mymap.size() << endl;

【问题讨论】:

  • 听起来像是某种“每桶”锁定……但这有意义吗?如果你只想改变元素,而不是容器,你可以让每个元素自己锁定。
  • 这个容器有多大?您可以将映射拆分为多个映射(或哈希映射)并使用哈希函数告诉您要在哪个映射上进行查找,这类似于映射/缩减方法,但只有在容器大小足够大时才实用这是值得的,所以你需要配置文件
  • @EdChum 目前,我已经能够比较 256^3 个值(约 1600 万)。但我想添加第四把钥匙。这需要大约 45 秒来计算和比较 256^3 个键。将此增加到 256^4,我正在查看大约 2.5 小时的比较。

标签: c++ multithreading hash map pthreads


【解决方案1】:

虽然上面已经回答了这个问题,但您可以通过替换 std::map::count() 并通过数组运算符插入更有效的方法来提高性能

其中一个 std::map::insert() 方法返回一对,如果元素已经存在于地图中,则 bool 成员将为 false。像这样的:

    int coll = 0;
typedef map<long, bool> MY_MAP_TYPE;
MY_MAP_TYPE mymap;
string temp;
long myhash;
for (int i = 0; i < 256; i++)
    for (int j = 0; j < 256; j++)
        for (int k = 0; k < 256; k++)
        {
            temp = i;
            temp += j;
            temp += k;
            temp += temp;
            myhash = hash(temp.c_str());
            if( mymap.insert( MY_MAP_TYPE::value_type( myhash, true ) ).second == false)
            {
                coll++;
                cout << "Collision at " << i << " " << j << " " << k << endl;
            }
        }

【讨论】:

  • 感谢您的建议。我创建了一个单独的question,所以你可以在那里回答。
  • 一群人打败了我 - 不用担心 - 很高兴为您提供帮助!
【解决方案2】:

这个算法似乎很容易与 OpenMP 并行化:

int coll = 0;
map<long, bool> mymap;

#pragma omp parallel for
for (int i = 0; i < 256; i++)
  for (int j = 0; j < 256; j++)
    for (int k = 0; k < 256; k++)
    {
      string temp = i;
      temp += j;
      temp += k;
      temp += temp;
      long myhash = hash(temp.c_str());

      if (mymap.count(myhash))
      {
        #pragma omp atomic
        coll++;
        cout << "Collision at " << i << " " << j << " " << k << endl;
      }
      else
      {
        #pragma omp critical
        mymap[myhash] = true;
      }
  }

一些解释:首先我们假设冲突非常罕见(如果冲突频繁,这将是一个非常糟糕的哈希表实现)。鉴于此,当一个线程插入某个键时,另一个线程同时插入完全相同的键是不太可能的,因为它碰巧偶然发现了一个散列到完全相同的键的不同值。此外,即使是这种情况,也只需其中一个将值设置为 true,因为它不能返回 false,并且后续的“插入”只会用 true 覆盖 true。因此,在我看来,除了coll 的增量,不需要进一步同步。

【讨论】:

  • 您介意详细说明您添加的#pragma 吗?除非我做错了什么,否则运行时间是一样的。
  • @Drise:这是大多数(如果不是全部)C++ 编译器(至少在 gcc 和 cl 上)上可用的 openMP 并行化库。只需#include &lt;omp.h&gt; 并使用-openmp 进行编译。 #pragma omp parallel for 表示应该创建一组线程,并且应该在它们之间拆分以下 for 循环的迭代。另一个 pragma 是确保潜在冲突操作的原子性。
  • #include && g++ main.cpp -openmp -o main --> 还是单线程的。
  • @Drise:嗯...试试-fopenmp。还可以尝试在最外层的 for 循环中打印 omp_get_num_threads() 的结果,看看它返回了什么。
  • @Drise:你是否在循环中设置了 tempmyhash 本地?
猜你喜欢
  • 2012-04-11
  • 1970-01-01
  • 2017-03-17
  • 2011-06-16
  • 2020-12-30
  • 1970-01-01
  • 1970-01-01
  • 2014-06-06
  • 1970-01-01
相关资源
最近更新 更多