在开始时使用所有可用数据构建大型(ish)无序集
Build large(ish) unordered set with all data available at the beginning
我有一种情况需要优化无序集的创建。预期的元素数量约为 5-25M。我的第一个想法是我应该事先准备好所有数据并做类似
的事情
unordered_set s(data);
而不是
for (auto& elem : data)
s.insert(elem);
STL无序集能否使用批量加载的方式加快创建速度?如果我在 table 构造之前知道预期的元素数量,我该如何调整散列 table 的参数(存储桶大小等)?
这个问题很广泛也很有趣。
首先,有一个特殊的方法叫做 reserve - 它允许您在实际插入之前为许多元素预分配存储空间。预先分配足够的内存(并避免在插入期间重新定位)是一种非常强大的方法,通常用于大型数据集。请注意,它也适用于各种标准容器,包括 vector
、unordered_map
等
其次,如果您使用的是 C++11,则在将元素插入容器时使用移动语义可能会受益(当然,前提是一旦放置它们,您就不需要它们在您的 Feed 中在集合中,这对于 5 到 2500 万个对象应该是正确的)。
这两项技术是一个好的开始。您可能需要通过设置不同的哈希函数,甚至选择 unordered_set 的不同实现来进一步调整它。但此时,您应该提供更多信息:您的价值对象是什么,它们的生命周期是什么;您认为什么插入时间在您的应用程序中是可以接受的。
编辑: 当然这都是关于 C++11 的,因为 unordered_set 在它之前是不可用的。我真丢人:)
My focus now is on whether I can use functions like rehash to notify the table for the upcoming size
假设你调用
unordered_set s(begin(data), end(data));
虽然标准没有规定实现,但好的实现将能够辨别元素的数量,并相应地预分配大小。如果你看gcc使用的源代码(我/usr/include/c++/5/tr1/hashtable.h
),例如,它使用
_M_bucket_count = std::max(_M_rehash_policy._M_next_bkt(__bucket_hint),
_M_rehash_policy.
_M_bkt_for_elements(__detail::
__distance_fw(__f,
__l)));
_M_buckets = _M_allocate_buckets(_M_bucket_count);
所以它已经根据元素的数量预先分配了大小。
不过,问题可能有所不同。如果您查看 the documentation,它表示:
constructs the container with the contents of the range [first, last). Sets max_load_factor() to 1.0.
这样可以节省 space,但可能会导致冲突。为了减少冲突,您可以使用
unordered_set s(begin(data), end(data), k * data.size());
其中 k > 1 是某个常数。这对应于 1 / k 的负载因子。 YMMV.
我有一种情况需要优化无序集的创建。预期的元素数量约为 5-25M。我的第一个想法是我应该事先准备好所有数据并做类似
的事情unordered_set s(data);
而不是
for (auto& elem : data)
s.insert(elem);
STL无序集能否使用批量加载的方式加快创建速度?如果我在 table 构造之前知道预期的元素数量,我该如何调整散列 table 的参数(存储桶大小等)?
这个问题很广泛也很有趣。
首先,有一个特殊的方法叫做 reserve - 它允许您在实际插入之前为许多元素预分配存储空间。预先分配足够的内存(并避免在插入期间重新定位)是一种非常强大的方法,通常用于大型数据集。请注意,它也适用于各种标准容器,包括 vector
、unordered_map
等
其次,如果您使用的是 C++11,则在将元素插入容器时使用移动语义可能会受益(当然,前提是一旦放置它们,您就不需要它们在您的 Feed 中在集合中,这对于 5 到 2500 万个对象应该是正确的)。
这两项技术是一个好的开始。您可能需要通过设置不同的哈希函数,甚至选择 unordered_set 的不同实现来进一步调整它。但此时,您应该提供更多信息:您的价值对象是什么,它们的生命周期是什么;您认为什么插入时间在您的应用程序中是可以接受的。
编辑: 当然这都是关于 C++11 的,因为 unordered_set 在它之前是不可用的。我真丢人:)
My focus now is on whether I can use functions like rehash to notify the table for the upcoming size
假设你调用
unordered_set s(begin(data), end(data));
虽然标准没有规定实现,但好的实现将能够辨别元素的数量,并相应地预分配大小。如果你看gcc使用的源代码(我/usr/include/c++/5/tr1/hashtable.h
),例如,它使用
_M_bucket_count = std::max(_M_rehash_policy._M_next_bkt(__bucket_hint),
_M_rehash_policy.
_M_bkt_for_elements(__detail::
__distance_fw(__f,
__l)));
_M_buckets = _M_allocate_buckets(_M_bucket_count);
所以它已经根据元素的数量预先分配了大小。
不过,问题可能有所不同。如果您查看 the documentation,它表示:
constructs the container with the contents of the range [first, last). Sets max_load_factor() to 1.0.
这样可以节省 space,但可能会导致冲突。为了减少冲突,您可以使用
unordered_set s(begin(data), end(data), k * data.size());
其中 k > 1 是某个常数。这对应于 1 / k 的负载因子。 YMMV.