如何将哈希值传递到无序映射以减少持有锁的时间?
How to pass hash value into unordered map to reduce time lock held?
我有一个用锁包裹的无序地图。
多个线程正在查找、插入。因此需要加锁。
我的问题是我不希望在无序映射代码中进行散列计算,因为该散列函数确实需要时间,因此在这段时间内不必要地持有锁。
我的想法是让调用者在锁外计算散列,并在查找、插入期间将其传递到无序映射中。
这可以用标准的无序地图实现吗?
您可以预先计算散列并将其存储在密钥中,然后在映射的互斥体锁定时使用自定义散列函数检索它:
#include <iostream>
#include <unordered_map>
#include <string>
#include <utility>
struct custom_key
{
custom_key(std::string s)
: data(std::move(s))
, hash_value(compute_hash(data))
{}
const std::string data;
static std::size_t compute_hash(const std::string& dat) {
return std::hash<std::string>()(dat);
}
// pre-computed hash
const std::size_t hash_value;
};
bool operator==(const custom_key& l, const custom_key& r) {
return l.data == r.data;
}
namespace std {
template<> struct hash<custom_key> {
using argument_type = custom_key;
using result_type = size_t;
result_type operator()(const argument_type& k) const {
return k.hash_value;
}
};
}
using namespace std;
auto main() -> int
{
unordered_map<custom_key, std::string> m;
m.emplace(custom_key("k1"s), "Hello, World");
return 0;
}
更新:
自从查看此答案后,我想到我们可以做得更好:
#include <iostream>
#include <unordered_map>
#include <string>
#include <utility>
/* the precompute key type */
template<class Type>
struct precompute_key {
/* may be constructed with any of the constructors of the underlying type */
template<class...Args>
precompute_key(Args &&...args)
: value_(std::forward<Args>(args)...), hash_(std::hash<Type>()(value_)) {}
operator Type &() { return value_; }
operator Type const &() const { return value_; }
auto hash_value() const { return hash_; }
auto value() const { return value_; }
auto value() { return value_; }
private:
Type value_;
std::size_t hash_;
};
template<class Type>
bool operator==(const precompute_key<Type> &l, const precompute_key<Type> &r) {
return l.value() == r.value();
}
namespace std {
template<class Type>
struct hash<precompute_key<Type>> {
auto operator()(precompute_key<Type> const &arg) const {
return arg.hash_value();
}
};
}
auto main() -> int {
std::unordered_map<precompute_key<std::string>, std::string> m;
m.emplace("k1", "Hello, World");
return 0;
}
我有一个用锁包裹的无序地图。
多个线程正在查找、插入。因此需要加锁。
我的问题是我不希望在无序映射代码中进行散列计算,因为该散列函数确实需要时间,因此在这段时间内不必要地持有锁。
我的想法是让调用者在锁外计算散列,并在查找、插入期间将其传递到无序映射中。
这可以用标准的无序地图实现吗?
您可以预先计算散列并将其存储在密钥中,然后在映射的互斥体锁定时使用自定义散列函数检索它:
#include <iostream>
#include <unordered_map>
#include <string>
#include <utility>
struct custom_key
{
custom_key(std::string s)
: data(std::move(s))
, hash_value(compute_hash(data))
{}
const std::string data;
static std::size_t compute_hash(const std::string& dat) {
return std::hash<std::string>()(dat);
}
// pre-computed hash
const std::size_t hash_value;
};
bool operator==(const custom_key& l, const custom_key& r) {
return l.data == r.data;
}
namespace std {
template<> struct hash<custom_key> {
using argument_type = custom_key;
using result_type = size_t;
result_type operator()(const argument_type& k) const {
return k.hash_value;
}
};
}
using namespace std;
auto main() -> int
{
unordered_map<custom_key, std::string> m;
m.emplace(custom_key("k1"s), "Hello, World");
return 0;
}
更新:
自从查看此答案后,我想到我们可以做得更好:
#include <iostream>
#include <unordered_map>
#include <string>
#include <utility>
/* the precompute key type */
template<class Type>
struct precompute_key {
/* may be constructed with any of the constructors of the underlying type */
template<class...Args>
precompute_key(Args &&...args)
: value_(std::forward<Args>(args)...), hash_(std::hash<Type>()(value_)) {}
operator Type &() { return value_; }
operator Type const &() const { return value_; }
auto hash_value() const { return hash_; }
auto value() const { return value_; }
auto value() { return value_; }
private:
Type value_;
std::size_t hash_;
};
template<class Type>
bool operator==(const precompute_key<Type> &l, const precompute_key<Type> &r) {
return l.value() == r.value();
}
namespace std {
template<class Type>
struct hash<precompute_key<Type>> {
auto operator()(precompute_key<Type> const &arg) const {
return arg.hash_value();
}
};
}
auto main() -> int {
std::unordered_map<precompute_key<std::string>, std::string> m;
m.emplace("k1", "Hello, World");
return 0;
}