c#到c++;字典到无序映射结果
我已经做了几年的c#现在,我正在努力学习一些新的东西。所以我决定看一看C++,用不同的方式来了解编程。 我读了很多书,但我今天才开始写一些代码 在运行VS2010的Windows 7/64位计算机上,我创建了两个项目: 1) 一个c#项目,让我以习惯的方式写东西。 2)一个C++“MaFrimeFrase'”项目,让我玩,试图实现同样的事情。据我所知,这不是一个.NET项目 我试着用10K值填充字典。由于某种原因,C++的数量级慢了。 这是下面的c#。注意,我在时间测量之后加入了一个函数,以确保它不会被编译器“优化”:c#到c++;字典到无序映射结果,c#,c++,visual-studio,performance,collections,C#,C++,Visual Studio,Performance,Collections,我已经做了几年的c#现在,我正在努力学习一些新的东西。所以我决定看一看C++,用不同的方式来了解编程。 我读了很多书,但我今天才开始写一些代码 在运行VS2010的Windows 7/64位计算机上,我创建了两个项目: 1) 一个c#项目,让我以习惯的方式写东西。 2)一个C++“MaFrimeFrase'”项目,让我玩,试图实现同样的事情。据我所知,这不是一个.NET项目 我试着用10K值填充字典。由于某种原因,C++的数量级慢了。 这是下面的c#。注意,我在时间测量之后加入了一个函数,以确保
var freq = System.Diagnostics.Stopwatch.Frequency;
int i;
Dictionary<int, int> dict = new Dictionary<int, int>();
var clock = System.Diagnostics.Stopwatch.StartNew();
for (i = 0; i < 10000; i++)
dict[i] = i;
clock.Stop();
Console.WriteLine(clock.ElapsedTicks / (decimal)freq * 1000M);
Console.WriteLine(dict.Average(x=>x.Value));
Console.ReadKey(); //Don't want results to vanish off screen
var freq=System.Diagnostics.Stopwatch.Frequency;
int i;
Dictionary dict=新字典();
var clock=System.Diagnostics.Stopwatch.StartNew();
对于(i=0;i<10000;i++)
dict[i]=i;
时钟停止();
控制台写入线(clock.ElapsedTicks/(十进制)频率*1000M);
Console.WriteLine(dict.Average(x=>x.Value));
Console.ReadKey()//不希望结果从屏幕上消失
这是c++,没有太多思考(尝试学习,对吧?)
int输入
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER t1, t2; // ticks
double elapsedTime;
// get ticks per second
QueryPerformanceFrequency(&frequency);
int i;
boost::unordered_map<int, int> dict;
// start timer
QueryPerformanceCounter(&t1);
for (i=0;i<10000;i++)
dict[i]=i;
// stop timer
QueryPerformanceCounter(&t2);
// compute and print the elapsed time in millisec
elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
cout << elapsedTime << " ms insert time\n";
int input;
cin >> input; //don't want console to disappear
大整数频率;//每秒滴答声
大整数t1,t2;//滴答声
双延时;
//每秒获得滴答声
QueryPerformanceFrequency(&frequency);
int i;
boost::无序映射dict;
//启动计时器
QueryPerformanceCounter(&t1);
对于(i=0;i,存储以升序添加的连续数字整数键序列肯定不是哈希表优化的目的
使用数组,或者生成随机值
并执行一些检索。哈希表针对检索进行了高度优化。Visual Studio TR1无序映射与stdext::哈希映射相同:
另一个线程询问它为什么执行缓慢,请查看我的答案,并链接到发现相同问题的其他线程。结论是在C++中使用另一个哈希映射实现:
<> p>记住,在C++中,优化释放版本与非优化调试版本相比C语言有很大的不同。 在插入元素之前,可以尝试使用<代码> Dig.ReHASH(n)< /代码>不同的(大)值<代码> n>代码>,并查看这会如何影响性能。内存分配。(当容器填充桶时发生的)在C++中比C中更昂贵,并且重散度也很重。对于<代码> STD::向量< /> >和<代码> STD::DeQue/Cuff>,模拟成员函数是代码> Reave
不同的重新缓存策略和负载系数阈值(查看max\u load\u factor
成员函数)也将极大地影响无序映射的性能
接下来,由于您使用的是VS2010,我建议您使用
标题中的std::unordered_map
。如果可以使用标准库,请不要使用boost
实际使用的哈希函数可能会极大地影响性能。您可以尝试以下方法:
struct custom_hash { size_t operator()(int x) const { return x; } };
并使用std::unordered_map
最后,我同意这是对哈希表的一种拙劣使用。使用随机值进行插入,您将获得更精确的情况。测试哈希表的插入速度一点都不愚蠢,但哈希表并不意味着要存储连续整数。为此,请使用向量。一个简单的分配器更改将减少错误那段时间过得很慢
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>, boost::fast_pool_allocator<std::pair<const int, int>>> dict;
boost::无序映射dict;
在我的系统上为0.9毫秒(从10毫秒之前开始)。这对我来说意味着,实际上,您的绝大多数时间根本不是花在哈希表上,而是花在分配器上。这是一个不公平的比较的原因是,您的GC永远不会在这样一个微不足道的程序中进行收集,这给了它不应有的性能优势,并且本机分配器对空闲内存进行了大量缓存-b但在这样一个简单的例子中,这永远不会起作用,因为您从未分配或解除分配过任何东西,所以没有任何东西可以缓存
最后,boostpool实现是线程安全的,而您从不使用线程,因此GC可以退回到单线程实现,这将更快
< P>我使用了一个手动滚动的、非释放的非线程安全池分配器,并将C++的0.25MS降至0.45毫秒(在我的机器上)。结论:由于两种语言的内存分配方案不同,原来的结果非常偏斜,一旦解决,差异就变得相对最小。
一个习惯(如Alexandre的回答所描述的)将我的C++时间降到0.34毫秒,现在比C<快。
static const int MaxMemorySize=800000;
静态int FreedMemory=0;
静态int分配器调用=0;
静态int-DeallocatorCalls=0;
模板
类本地分配器
{
公众:
std::向量*内存;
int*使用的电流;
类型定义T值_类型;
typedef值\u type*指针;
类型定义常量值\u类型*常量指针;
类型定义值\u类型和参考;
类型定义常量值\u类型和常量参考;
typedef std::size\u t size\u type;
typedef std::大小差异类型;
模板结构重新绑定{typedef LocalAllocator other;};
模板
LocalAllocator(constlocalallocator&other){
CurrentUsed=其他。CurrentUsed;
内存=其他内存;
}
LocalAllocator(std::vector*ptr,int*已使用){
当前使用=已使用;
内存=ptr;
}
模板LocalAllocator(LocalAllocator&&other){
CurrentUsed=其他。CurrentUsed;
内存=其他内存;
}
指针地址(引用r){return&r;}
常量指针地址(常量引用s){return&r;}
size_type max_size()常量{返回MaxMemorySize;
static const int MaxMemorySize = 800000;
static int FreedMemory = 0;
static int AllocatorCalls = 0;
static int DeallocatorCalls = 0;
template <typename T>
class LocalAllocator
{
public:
std::vector<char>* memory;
int* CurrentUsed;
typedef T value_type;
typedef value_type * pointer;
typedef const value_type * const_pointer;
typedef value_type & reference;
typedef const value_type & const_reference;
typedef std::size_t size_type;
typedef std::size_t difference_type;
template <typename U> struct rebind { typedef LocalAllocator<U> other; };
template <typename U>
LocalAllocator(const LocalAllocator<U>& other) {
CurrentUsed = other.CurrentUsed;
memory = other.memory;
}
LocalAllocator(std::vector<char>* ptr, int* used) {
CurrentUsed = used;
memory = ptr;
}
template<typename U> LocalAllocator(LocalAllocator<U>&& other) {
CurrentUsed = other.CurrentUsed;
memory = other.memory;
}
pointer address(reference r) { return &r; }
const_pointer address(const_reference s) { return &r; }
size_type max_size() const { return MaxMemorySize; }
void construct(pointer ptr, value_type&& t) { new (ptr) T(std::move(t)); }
void construct(pointer ptr, const value_type & t) { new (ptr) T(t); }
void destroy(pointer ptr) { static_cast<T*>(ptr)->~T(); }
bool operator==(const LocalAllocator& other) const { return Memory == other.Memory; }
bool operator!=(const LocalAllocator&) const { return false; }
pointer allocate(size_type count) {
AllocatorCalls++;
if (*CurrentUsed + (count * sizeof(T)) > MaxMemorySize)
throw std::bad_alloc();
if (*CurrentUsed % std::alignment_of<T>::value) {
*CurrentUsed += (std::alignment_of<T>::value - *CurrentUsed % std::alignment_of<T>::value);
}
auto val = &((*memory)[*CurrentUsed]);
*CurrentUsed += (count * sizeof(T));
return reinterpret_cast<pointer>(val);
}
void deallocate(pointer ptr, size_type n) {
DeallocatorCalls++;
FreedMemory += (n * sizeof(T));
}
pointer allocate() {
return allocate(sizeof(T));
}
void deallocate(pointer ptr) {
return deallocate(ptr, 1);
}
};
int main() {
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER t1, t2; // ticks
double elapsedTime;
// get ticks per second
QueryPerformanceFrequency(&frequency);
std::vector<char> memory;
int CurrentUsed = 0;
memory.resize(MaxMemorySize);
struct custom_hash {
size_t operator()(int x) const { return x; }
};
boost::unordered_map<int, int, custom_hash, std::equal_to<int>, LocalAllocator<std::pair<const int, int>>> dict(
std::unordered_map<int, int>().bucket_count(),
custom_hash(),
std::equal_to<int>(),
LocalAllocator<std::pair<const int, int>>(&memory, &CurrentUsed)
);
// start timer
std::string str;
QueryPerformanceCounter(&t1);
for (int i=0;i<10000;i++)
dict[i]=i;
// stop timer
QueryPerformanceCounter(&t2);
// compute and print the elapsed time in millisec
elapsedTime = ((t2.QuadPart - t1.QuadPart) * 1000.0) / frequency.QuadPart;
std::cout << elapsedTime << " ms insert time\n";
int input;
std::cin >> input; //don't want console to disappear
}