c#到c ++字典到unordered_map结果

Car*_*los 10 c# c++ collections performance visual-studio

我现在已经做了几年c#,我正在尝试学习一些新东西.所以我决定看看c ++,以不同的方式了解编程.

我一直在做大量阅读,但我今天刚开始写一些代码.

在运行VS2010的Windows 7/64位机器上,我创建了两个项目:1)一个c#项目,让我按照我习惯的方式编写东西.2)一个c ++"makefile"项目,让我玩,试图实现相同的东西.据我所知,这不是一个.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
Run Code Online (Sandbox Code Playgroud)

这是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
Run Code Online (Sandbox Code Playgroud)

现在,一些警告.我设法找到了这个相关的SO问题.其中一个人写了一篇长篇答案,提到WOW64扭曲结果.我已经将项目设置为发布并经历了c ++项目的"属性"选项卡,启用听起来像它的所有内容都会让它变得快速.将平台更改为x64,但我不确定是否解决了他的问题.我对编译器选项没有经验,也许你们有更多的线索?

哦,结果:c#:0.32ms c ++:8.26ms.这有点奇怪.我是否误解了什么.Quad意味着什么?我从Web上的某个地方复制了c ++计时器代码,经历了所有的boost安装和include/libfile rigmarole.或许我实际上是在不知不觉中使用不同的乐器?或者有一些我没有使用的关键编译选项?或者c#代码可能是优化的,因为平均值是常数?

这是c ++命令行,来自Property页面 - > C/C++ - >命令行:/ I"C:\ Users\Carlos\Desktop\boost_1_47_0"/ Zi/nologo/W3/WX-/MP/Ox/Oi/Ot/GL/D"_MBCS"/ Gm-/EHsc/GS-/Gy-/arch:SSE2/fp:fast/Zc:wchar_t/Zc:forScope /Fp"x64\Release\MakeTest.pch"/ Fa"x64\Release \"/ Fo"x64\Release \"/ Fd"x64\Release\vc100.pdb"/ Gd/errorReport:queue

任何帮助将不胜感激,谢谢.

Pup*_*ppy 12

一个简单的分配器更改将减少很多时间.

boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>, boost::fast_pool_allocator<std::pair<const int, int>>> dict;
Run Code Online (Sandbox Code Playgroud)

在我的系统上0.9ms(从之前的10ms).这对我来说,实际上,你的绝大部分时间都不是花在哈希表中,而是花在分配器上.这是一个不公平的比较的原因是因为你的GC永远不会在这样一个简单的程序中收集,给它带来不正当的性能优势,并且原生分配器会对可用内存进行重要的缓存 - 但这种情况永远不会发生在如此微不足道的事情中例如,因为您从未分配或取消分配任何内容,因此无需缓存.

最后,Boost池实现是线程安全的,而您从不使用线程,因此GC可以回退到单线程实现,这将更快.

我使用了一个手动,非释放的非线程安全池分配器,对于C++,在C#(在我的机器上)下降到0.525ms到0.45ms.结论:由于两种语言的内存分配方案不同,原始结果非常偏斜,一旦解决了这些问题,差异就会变得相对最小.

自定义哈希(如Alexandre的回答中所述)将我的C++时间减少到0.34ms,现在比C#快.

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
}
Run Code Online (Sandbox Code Playgroud)