【发布时间】:2020-06-03 00:26:29
【问题描述】:
我有很多键(c 字符串),我想预先计算它们的哈希值。我制作了一个包含关键数据及其散列的结构。我将这些结构推入向量并将向量分组。每组键将由一个线程进行哈希处理。
小例子:
struct Key
{
char* data; // mostly 10 character strings
uint64_t hash; // init with 0 and compute later
};
// hash group of keys
static void hash_keys(size_t idx_start, size_t const& length)
{
size_t idx_end = idx_start + length;
for (size_t i = idx_start; i < idx_end; i++)
{
Key* k = keys[i];
// hash key by murmurhash2 or djb2 hash function
k->hash = external_hash_key(k->data);
}
}
vector<Key*> keys;
// push all keys into keys vector
external_fill_keys();
size_t num_of_keys = keys.size();
// start threads
vector<thread> workers;
size_t length = num_of_keys / NUM_OF_WORKERS;
size_t remainder = num_of_keys % NUM_OF_WORKERS;
for (size_t i = 0; i < NUM_OF_WORKERS; i++)
workers.push_back(
thread(
hash_keys,
i * length, length
)
);
hash_keys(NUM_OF_WORKERS * length, remainder);
// join threads
for (auto& worker : workers)
worker.join();
我有大约 3 000 000 把钥匙。如果我用单线程运行代码 - 只需调用 hash_keys(0, keys.size()) - 我会得到 4.0 秒的估计时间。如果我用 4 个工作线程运行代码,我会得到 5.5 秒。
问题是为什么这么慢?不推荐从多个线程中读取相同的向量吗?我怎样才能利用这些线程并在更短的时间内做到这一点?
【问题讨论】:
-
尝试使用
size_t i = idx_start代替hash_keys。看起来您正在多次散列较早的键。 -
@FrançoisAndrieux 不抱歉。那是一个错字。我最初只使用
idx_start作为它的副本,我不需要局部变量i。我编辑了那个。 -
perf 说什么?
-
我的猜测是您正在破坏 L2 或 L3 缓存。您可以尝试按线程交错散列,而不是为每个分配一个大块(间隔很远)。任何人都可以猜测
char *和Key*都是在内存中创建的,但它们可能很接近。 -
尝试优化解决方案,例如 tbb::parallel_for
标签: c++ multithreading vector hash