Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c#到c++;字典到无序映射结果_C#_C++_Visual Studio_Performance_Collections - Fatal编程技术网

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#。注意,我在时间测量之后加入了一个函数,以确保

我已经做了几年的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
}