为什么一个向量上的多线程操作很慢

Why is multi threaded operation on one vector slow?

本文关键字:多线程 操作 向量 一个 为什么      更新时间:2023-10-16

我有很多键(c-string(,我想预先计算它们的哈希值。我制作了一个结构,用于保存密钥数据及其哈希。我把这些结构推到向量中,然后把向量分组。每组密钥将由一个线程进行散列。

最小示例:

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();

我有大约3000把钥匙。如果我用单线程运行代码——只调用hash_keys(0, keys.size())——我得到了4.0秒的估计时间。如果我用4个工作线程运行代码,我将获得5.5秒的时间。

问题是为什么速度较慢?是否不建议从多个线程读取相同的矢量?我如何利用这些线程并在更短的时间内完成这项工作?

原来我的代码有两个问题:

  • 错误共享,当一个线程更新了一个键的哈希时,它试图写入与相邻线程相同的缓存行,这大大降低了执行速度
  • 每个键都是通过单个new调用创建的,而不是一次创建多个键(在示例中不可见,此问题发生在函数external_fill_keys中(

解决方案是为每个线程创建独立的键数组,在连接线程后,数组将连接到一个大数组中。