簡體   English   中英

與Java相比,C ++移動語義性能

[英]C++ move semantics performance compared to Java

我想證明使用移動語義的C ++比Java快得多,我驚訝地發現它實際上要慢得多。

編輯:我有意插入向量中的元素,盡管我知道這樣的插入更適合列表。 然而,這是在C ++中基准移動語義的典型基准。 因此,我想使用此特定測試來查看與Java的差異。

我可能犯了一個錯誤:我所做的是以下兩個程序: http//melpon.org/wandbox/permlink/abZlAmZrOC9fJV8rhttp://melpon.org/wandbox/permlink/3QGQMEIoF5kc3xtY

結果是非常令人驚訝的,因為它表明Java更快,因為6! 我認為代碼可能在不同的機器上運行,因此我在我的機器上使用msvc 2012x64和以下編譯選項進行了嘗試:

cl / EHsc / Ox cppPerf.cpp

相比

jdk1.8.0_73 \\ bin \\ javac.exe javaPerf.java

結果給出了10個有利於java的比例!

怎么可能是java比使用移動語義的C ++快得多?

另一個有趣的觀點是,使用Java7可以提供遠離Java8的性能,但仍然比C ++更好: http ://melpon.org/wandbox/permlink/CJXwHCwp5rGwr1Gc

編輯:我刪除了可通過鏈接訪問的代碼。

編輯:

我想我發現了問題,Java優化了一些代碼。 這些是更新版本,表明C ++更快: http//melpon.org/wandbox/permlink/GsflztloK7ir2jea http://melpon.org/wandbox/permlink/CLwKoZzbfqstDOfn

編輯:這是另一個測試,它使用@dasblinkenlight建議的參考提供C ++的基准測試,它顯示了C ++和Java之間的巨大差異(注意我注意使用unique_ptr因為我想要檢查C ++ 03而我想避免提升因此沒有scoped_ptr): http//melpon.org/wandbox/permlink/bYQjNpjsIZu3vp3f

結果是:

C++14:
USE_MOVE  USE_REFERENCES  TIME
    Y             Y         30 to 55ms
    N             Y         30 to 60ms

    Y             N         370 to  210ms
    N             N         390 to  270ms (Implicit move of elements in vectors)

C++03:
USE_REFERENCES  TIME
        Y         45 to   70ms
        N       1370 to 1650ms (No implicit move of elements in vectors)

Java:
               11300 to 13000 ms

問題是你不是在比較蘋果和蘋果:

  • Java的String是不可變的,因此將它們復制到容器中相當於存儲引用。
  • 更重要的是,您的代碼插入向量的開頭,因此向量最終執行O(n 2 )個復制操作。

我認為第二點說明了差異的主要部分。 最后插入vec.insert(vec.end(), std::move(myString))或者使用push_back和Java中的相應更改應該使得時間更加接近。

要修復第一個點,請動態分配字符串,並改為生成std::unique_ptr<std::string>的向量。 這將復制指針而不是復制內容,從而使性能時間更加接近。

我想證明使用移動語義的C ++比Java快得多,我驚訝地發現它實際上要慢得多。

如果有人要求你證明C ++比Java更快而不是轉身離開。 業界不需要這樣的證據。

結果是非常令人驚訝的,因為它表明Java更快,因為6!

不。

在堅果殼中,這就是C ++所做的:

for 10000 times, Do:
 1. measure the literal size
 2. allocate enough memory to hold the literal (EXPENSIVE!)
 3. Copy the literal memory into the newly allocated memory 
 4. check if there is enough memory in the vector to hold current size + 1 string objects, if false - allocate new chunk and move all the existing objects to that chunk of memory (EXPENSIVE!)
 5. move the existing strings inside the vector forward by 1 index (EXPENSIVE!)
 6. move the string object to `vec[0]`
for 10000 times, Do:
 7. build new string objects from r-value reference returned from `vec[i]`
 8. free the string memory (EXPENSIVE!)

你從文字中構建了10000個字符串對象,所以你必須對所有10000個內存塊進行編碼,一次又一次地重新計算文字長度並重復移動向量內的字符串對象。

Java的作用:

 1. when the program goes up, the JVM builds a string object containing the literal just once
for 10000 , Do: 
 2. copy the pointer (Cheap.)
 3. check if there is enough memory in the vector to hold current size + 1 string pointers , if not - allocate new chunk of memory and copy the existing pointers to that memory block (Cheap.) 
 4. move the existing string pointers inside the vector forward by 1 index (Cheap, probably uses `memmove` behind the scenes)
 5. copy the pointer to `Vector[0]` (Cheap.) 
for 10000 , Do:
 6. Copy the string pointer pointed by `vec[i]`

字符串對象只創建一次,並且一次又一次地復制其指針。 Java程序與C ++程序完全不同。

所以基本上,這個程序只顯示復制指針比復制對象便宜。 沒什么我們不知道的。 如果你真的想做公平的基准測試,要么是C ++中的基准字符串指針,要么讓Java程序一次又一次地重新克隆字符串。

如果插入不在最后,C ++ vectorinsert方法使用重新分配:

因為向量使用數組作為其底層存儲, 所以在向量末端以外的位置插入元素會導致容器將位置之后的所有元素重新定位到新位置。 與通過其他類型的序列容器(例如list或forward_list)對相同操作執行的操作相比,這通常是低效操作

list替換vector ,您將看到性能幾乎相同。

作為抽象類型的向量在Java和C ++中幾乎相同,但它們各自的實現可能會嚴重不同...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM