- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我知道代码会变慢,但为什么这么慢?我该如何编码才能避免这种减速?
std::unordered_map 在内部使用其他容器,而这些容器使用迭代器。构建调试时,默认_ITERATOR_DEBUG_LEVEL=2。这会打开 iterator debugging .有时我的代码没有受到太大影响,有时运行起来非常慢。
我可以通过在我的项目属性 >> C++ >> 预处理器 >> 预处理器定义中设置 _ITERATOR_DEBUG_LEVEL=0 来加速我的示例。但是作为this link建议,我不能在我的真实项目中这样做。就我而言,我与 MSVCMRTD.lib 发生冲突,其中包含使用 _ITERATOR_DEBUG_LEVEL=2 构建的 std::basic_string。我知道我可以通过静态链接到 CRT 来解决这个问题。但如果我可以修复代码,我宁愿不这样做,这样问题就不会出现。
我可以做出改变来改善这种情况。但我只是在不理解它们为什么起作用的情况下尝试。例如,前 1000 个插入以全速运行。但是,如果我将 O_BYTE_SIZE 更改为 1,则第一个插入与其他所有内容一样慢。这看起来像是一个小的改变(不一定是好的改变。)
This , this , 和 this也阐明了一些问题,但不要回答我的问题。
我使用的是 Visual Studio 2010(这是遗留代码。)我创建了一个 Win32 控制台应用程序并添加了这段代码。
main.cpp
#include "stdafx.h"
#include "OString.h"
#include "OTHashMap.h"
#include <cstdio>
#include <ctime>
#include <iostream>
// Hash and equal operators for map
class CRhashKey {
public:
inline unsigned long operator() (const OString* a) const { return a->hash(); }
};
class CReqKey {
public:
inline bool operator() (const OString& x, const OString& y) const { return strcmp(x.data(),y.data()) != 0; }
inline bool operator() (const OString* x, const OString& y) const { return operator()(*x,y); }
inline bool operator() (const OString& x, const OString* y) const { return operator()(x,*y); }
inline bool operator() (const OString* x, const OString* y) const { return operator()(*x,*y); }
};
int _tmain(int argc, _TCHAR* argv[])
{
const int CR_SIZE = 1020007;
CRhashKey h;
OTPtrHashMap2<OString, int, CRhashKey, CReqKey> *code_map =
new OTPtrHashMap2 <OString, int, CRhashKey, CReqKey>(h, CR_SIZE);
const clock_t begin_time = clock();
for (int i=1; i<=1000000; ++i)
{
char key[10];
sprintf(key, "%d", i);
code_map->insert(new OString(key), new int(i));
//// Check hash values
//OString key2(key);
//std::cout << i << "\t" << key2.hash() << std::endl;
// Check timing
if ((i % 100) == 0)
{
std::cout << i << "\t" << float(clock() - begin_time) / CLOCKS_PER_SEC << std::endl;
}
}
std::cout << "Press enter to exit" << std::endl;
char buf[256];
std::cin.getline(buf, 256);
return 0;
}
OTHashMap.h
#pragma once
#include <fstream>
#include <unordered_map>
template <class K, class T, class H, class EQ>
class OTPtrHashMap2
{
typedef typename std::unordered_map<K*,T*,H,EQ> OTPTRHASHMAP_INTERNAL_CONTAINER;
typedef typename OTPTRHASHMAP_INTERNAL_CONTAINER::iterator OTPTRHASHMAP_INTERNAL_ITERATOR;
public:
OTPtrHashMap2(const H& h, size_t defaultCapacity) : _hashMap(defaultCapacity, h) {}
bool insert(K* key, T* val)
{
std::pair<OTPTRHASHMAP_INTERNAL_ITERATOR,T> retVal = _hashMap.insert(std::make_pair<K*,T*>(key, val));
return retVal.second != NULL;
}
OTPTRHASHMAP_INTERNAL_CONTAINER _hashMap;
private:
};
OString.h
#pragma once
#include <string>
class OString
{
public:
OString(const std::string& s) : _string (s) { }
~OString(void) {}
static unsigned hash(const OString& s) { return unsigned (s.hash()); }
unsigned long hash() const
{
unsigned hv = static_cast<unsigned>(length());
size_t i = length() * sizeof(char) / sizeof(unsigned);
const char * p = data();
while (i--) {
unsigned tmp;
memcpy(&tmp, p, sizeof(unsigned));
hashmash(hv, tmp);
p = p + sizeof(unsigned);
}
if ((i = length() * sizeof(char) % sizeof(unsigned)) != 0) {
unsigned h = 0;
const char* c = reinterpret_cast<const char*>(p);
while (i--)
{
h = ((h << O_BYTE_SIZE*sizeof(char)) | *c++);
}
hashmash(hv, h);
}
return hv;
}
const char* data() const { return _string.c_str(); }
size_t length() const { return _string.length(); }
private:
std::string _string;
//static const unsigned O_BYTE_SIZE = 1;
static const unsigned O_BYTE_SIZE = 8;
static const unsigned O_CHASH_SHIFT = 5;
inline void hashmash(unsigned& hash, unsigned chars) const
{
hash = (chars ^
((hash << O_CHASH_SHIFT) |
(hash >> (O_BYTE_SIZE*sizeof(unsigned) - O_CHASH_SHIFT))));
}
};
最佳答案
我找到了足够多的答案。碰撞是减速的根源。
编辑 2:-- 另一个修复是在 main.cpp 中的 #include 周围添加它 --
// Iterator debug checking makes the Microsoft implementation of std containers
// *very* slow in debug builds for large containers. It must only be undefed around
// STL includes. Otherwise we get linker errors from the debug C runtime library,
// which was built with _ITERATOR_DEBUG_LEVEL set to 2.
#ifdef _DEBUG
#undef _ITERATOR_DEBUG_LEVEL
#endif
#include <unordered_map>
#ifdef _DEBUG
#define _ITERATOR_DEBUG_LEVEL 2
#endif
std::unordered_map 在
_Hash 包含这个(高度缩写)
template<...>
class _Hash
{
typedef list<typename _Traits::value_type, ...> _Mylist;
typedef vector<iterator, ... > _Myvec;
_Mylist _List; // list of elements, must initialize before _Vec
_Myvec _Vec; // vector of list iterators, begin() then end()-1
};
所有值都存储在_List 中。
_Vec 是指向 _List 的迭代器 vector 。它将 _List 分成桶。 _Vec 有一个指向每个桶的开头和结尾的迭代器。因此,如果映射有 1M 个桶(不同的键哈希),_Vec 有 2M 个迭代器。
当一个键/值对被插入映射时,通常会创建一个新的桶。该值被推到列表的开头。键的散列是 _Vec 中放置两个新迭代器的位置。这很快,因为它们指向列表的开头。
如果桶已经存在,则必须将新值插入到 _List 中现有值的旁边。这需要在列表中间插入一个项目。必须更新现有的迭代器。显然,当启用迭代器调试时,这需要大量工作。代码在
里,我没有单步执行。
为了了解工作量,我使用了一些无意义的散列函数,这些函数使用起来很糟糕,但在插入时会产生很多冲突或很少的冲突。
添加到 OString.h
static unsigned hv2;
// Never collides. Always uses the next int as the hash
unsigned long hash2() const
{
return ++hv2;
}
// Almost never collides. Almost always gets the next int.
// Gets the same int 1 in 200 times.
unsigned long hash3() const
{
++hv2;
unsigned long lv = (hv2*200UL)/201UL;
return (unsigned)lv;
}
// A best practice hash
unsigned long hash4() const
{
std::hash<std::string> hasher;
return hasher(_string);
}
// Always collides. Everything into bucket 0.
unsigned long hash5() const
{
return 0;
}
添加到 main.cpp
// Hash and equal operators for map
class CRhashKey {
public:
//inline unsigned long operator() (const OString* a) const { return a->hash(); }
//inline unsigned long operator() (const OString* a) const { return a->hash2(); }
//inline unsigned long operator() (const OString* a) const { return a->hash3(); }
//inline unsigned long operator() (const OString* a) const { return a->hash4(); }
inline unsigned long operator() (const OString* a) const { return a->hash5(); }
};
unsigned OString::hv2 = 0;
结果是戏剧性的。没有现实的哈希会起作用。
我的选择是
关于c++ - 为什么迭代器调试在调试版本中会减慢 std::unordered_map 200x?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56961756/
如果您有超过 1 个具有相同类名的(动态)文本框,并使用 jquery 循环遍历每个所述文本框,您是否可以假设每次选择文本框的顺序都是相同的? 示例: 文本框 1 值 = 1文本框 2 值 = 2文本
有人知道为什么这段代码无法顺利运行吗?它似乎不喜欢使用yield关键字进行迭代:我正在尝试从任何级别的列表或字典中挖掘所有数字(对列表特别感兴趣)。在第二次迭代中,它找到 [2,3] 但无法依次打印
我关于从 mysql 数据库导出数据并将其保存到 Excel 文件(多表)的创建脚本。我需要让细胞动态基因化。该脚本正确地显示了标题,但数据集为空。当我“回显”$value 变量时,我检查了数据是否存
我正在尝试在 Python 中运行模拟,由此我绘制了一个数组的随机游走图,给定了两个变量参数的设定水平。 但是,我遇到了一个问题,我不确定如何迭代以便生成 250 个不同的随机数以插入公式。例如我已经
我是学习 jquery 的新手,所以如果这是一个相对简单的问题,我深表歉意。我有一个 ID 为 ChartstoDisplay 的 asp.net 复选框列表。我正在尝试创建 jquery 来根据是否
我正在尝试根据在任意数量的部分中所做的选择找出生成有效案例列表的最佳方法。也许它不是真正的算法,而只是关于如何有效迭代的建议,但对我来说这似乎是一个算法问题。如果我错了,请纠正我。实现实际上是在 Ja
如果我使用 sr1 为 www.google.com 发送 DNSQR,我会收到几个 DNSRR(s) 作为回复,例如(使用 ans[DNSRR].show() 完成): ###[ DNS Resou
假设有这样一个实体类 @Entity public class User { ... public Collection followers; ... } 假设用户有成千上万的用户关注者。我想分页..
这个问题已经有答案了: 已关闭11 年前。 Possible Duplicate: Nested jQuery.each() - continue/break 这是我的代码: var steps =
我刚从 F# 开始,我想遍历字典,获取键和值。 所以在 C# 中,我会说: IDictionary resultSet = test.GetResults; foreach (DictionaryEn
我知道已经有很多关于如何迭代 ifstream 的答案,但没有一个真正帮助我找到解决方案。 我的问题是:我有一个包含多行数据的txt文件。 txt 文件的第一行告诉我其余数据是如何组成的。例如这是我的
我有 12 个情态动词。我想将每个模态的 .modal__content 高度与 viewport 高度 进行比较,并且如果特定模态 .modal__content 高度 vh addClass("c
在此JSFiddle (问题代码被注释掉)第一次单击空单元格会在隐藏输入中设置一个值,并将单元格的背景颜色设置为绿色。单击第二个空表格单元格会设置另一个隐藏输入的值,并将第二个单元格的背景颜色更改为红
这是一个非常具体的问题,我似乎找不到任何特别有帮助的内容。我有一个单链表(不是一个实现的链表,这是我能找到的全部),其中节点存储一个 Student 对象。每个 Student 对象都有变量,尽管我在
有没有办法迭代 IHTMLElementCollection? 比如 var e : IHTMLLinkElement; elementCollection:IHTMLElementCollect
我正在尝试用 Java 取得高分。基本上我想要一个 HashMap 来保存 double 值(因此索引从最高的 double 值开始,这样我更容易对高分进行排序),然后第二个值将是客户端对象,如下所示
我想在宏函数中运行 while/until 循环,并限制其最大迭代次数。我找到了如何在“通常”sas 中执行此操作: data dataset; do i=1 to 10 until(con
Iterator iterator = plugin.inreview.keySet().iterator(); while (iterator.hasNext()) { Player key
晚上好我有一个简单的问题,我警告你我是序言的新手。假设有三个相同大小的列表,每个列表仅包含 1、0 或 -1。我想验证对于所有 i,在三个列表的第 i 个元素中,只有一个非零。 此代码针对固定的 i
我在 scheme 中构建了一个递归函数,它将在某些输入上重复给定函数 f, n 次。 (define (recursive-repeated f n) (cond ((zero? n) iden
我是一名优秀的程序员,十分优秀!