我從事程式設計的那段時間,聽說C和C是速度標準。最快中的最快,直接編譯為彙編程式碼,速度上沒有任何東西可以與 C 或 C 競爭。而且,似乎沒有人挑戰這個共同信念。
運算效能
顯然,數字算術運算在 C 中的運行速度必須比在任何其他語言中快得多。但他們有嗎?
前段時間,我決定為許多不同的語言編寫一組簡單的基準測試,看看速度有多大差異。
想法很簡單:從零開始,使用直接計算來找到十億個整數的總和。有些編譯器(例如rustc)用公式表達式取代這個簡單的循環,當然,公式表達式將在恆定的時間內進行計算。用這樣的編譯器來避免這種情況。我在數位成本運算中使用了類似的方法,例如位元或。
得到結果後,我非常驚訝。我的世界觀發生了翻天覆地的變化,我不得不重新考慮我所知道的關於程式語言速度的一切。
您可以在下表中看到我的結果:
Linux 64 位元,1.1 GHz CPU,4GB RAM
Language | compiler/version/args | time |
---|---|---|
Rust (bitwise or instead of ) | rustc 1.75.0 with -O3 | 167 ms |
C | gcc 11.4.0 with -O3 | 335 ms |
NASM | 2.15.05 | 339 ms |
Go | 1.18.1 | 340 ms |
Java | 17.0.13 | 345 ms |
Common Lisp | SBCL 2.1.11 | 1 sec |
Python 3 | pypy 3.8.13 | 1.6 sec |
Clojure | 1.10.2 | 9 sec |
Python 3 | cpython 3.10.12 | 26 sec |
Ruby | 3.0.2p107 | 38 sec |
您可以在這裡找到所有測試來源:
https://github.com/Taqmuraz/speed-table
因此,如我們所看到的,C 並不比 Java 快很多,差異約為 3%。此外,我們還發現其他編譯語言的算術運算效能與 C 非常接近(Rust 甚至更快)。使用 JIT 編譯器 編譯的動態語言顯示出更糟糕的結果 - 主要是因為算術運算被包裝到動態分派的函數中。
解釋型動態語言沒有 JIT 編譯器表現出最差的效能,這並不奇怪。
記憶體分配效能
在那次慘敗之後,C 粉絲會說 C 中的記憶體分配要快得多,因為你直接從系統分配它,而不是要求 GC。
現在和之後我將使用 GC 術語作為 垃圾收集器 和 託管堆,取決於上下文。
那麼,為什麼人們認為 GC 這麼慢?事實上,GC已經預先分配了內存,分配就是簡單地將指針向右移動。大多數情況下 GC 使用系統呼叫將分配的記憶體填充為零,類似於 C 中的 memset,因此需要 恆定時間。而 C 中的記憶體分配需要不確定的時間,因為它取決於系統和已經分配的記憶體。
但是,即使考慮到這些知識,我也無法期望 Java 能達到如此好的結果,您可以在下表中看到:
1.1 GHz 2 cores, 4 GB RAM |
Running tests on single thread. |
Result format : "Xms-Yms ~Z ms" means tests took from X to Y milliseconds, and Z milliseconds in average |
分配整數數組
integers array size | times | Java 17.0.13 new[] | C gcc 11.4.0 malloc | Common Lisp SBCL 2.1.11 make-array |
---|---|---|---|---|
16 | 10000 | 0-1ms, ~0.9ms | 1-2ms, ~1.2ms | 0-4ms, ~0.73ms |
32 | 10000 | 1-3ms, ~1.7ms | 1-3ms, ~1.7ms | 0-8ms, ~2.ms |
1024 | 10000 | 6-26ms, ~12ms | 21-46ms, ~26ms | 12-40ms, ~7ms |
2048 | 10000 | 9-53ms, ~22ms | 24-52ms, ~28ms | 12-40ms, ~19ms |
16 | 100000 | 0-9ms, ~2ms | 6-23ms, ~9ms | 4-24ms, ~7ms |
32 | 100000 | 0-14ms, ~3ms | 10-15ms, ~11ms | 3-8ms, ~7ms |
1024 | 100000 | 0-113ms, ~16ms | 234-1156ms, ~654ms | 147-183ms, ~155ms |
2048 | 100000 | 0-223ms, ~26ms | 216-1376ms, ~568ms | 299-339ms, ~307ms |
為 Person 類別的實例指派一個整數欄位。
how many instances | Java 17.0.3 new Person(n) | C g 11.4.0 new Person(n) |
---|---|---|
100000 | 0-6ms, ~1.3ms | 4-8ms, ~5ms |
1 million | 0-11ms, ~2ms | 43-69ms, ~47ms |
1 billion | 22-50ms, ~28ms | process terminated |
您可以在這裡找到所有測試來源:
https://github.com/Taqmuraz/alloc-table
在那裡我總共測試了四種語言:C、C、Java 和 Lisp。而且,帶有 GC 的語言總是顯示出更好的結果,儘管我對它們的測試比 C 和 C 嚴格得多。例如,在 Java 中,我透過虛擬函數呼叫分配內存,因此它可能不會被靜態優化,而在 Lisp 中,我正在檢查分配數組的第一個元素,因此編譯器不會跳過分配呼叫。
釋放記憶體
C 粉絲仍然有動力去保護他們的信仰,所以,他們說「是的,你分配記憶體確實更快,但你必須在之後釋放它!」。
真的。而且,突然之間,GC 釋放記憶體的速度比 C 還要快。但是如何呢?想像一下,我們從 GC 進行了 100 萬次分配,但後來我們的程式中只引用了 1000 個物件。而且,比方說,這些物件分佈在所有這麼長的記憶體範圍內。 GC 進行堆疊跟踪,找到那 1000 個「活動」對象,將它們移動到上一代堆疊峰值,並將堆疊峰值指針放在最後一個物件之後。就這樣。
所以,無論你分配了多少物件,GC的工作時間取決於之後你保留了多少物件。
而且,與此相反,在 C 中,您必須手動釋放所有分配的內存,因此,如果您分配內存 100 萬次,您也必須進行 100 萬次釋放調用(否則將會出現內存洩漏)。這表示GC 的O(1)-O(n) 與C 的O(n) 或更差,其中n是之前發生的分配次數。
概括
所以,我想鞏固垃圾收集語言對 C 和 C 的勝利。這是總結表:
demands | languages with GC | C/C |
---|---|---|
arithmetic | fast with JIT | fast |
allocating memory | fast O(1) | slow |
releasing memory | fast O(1) best case, O(n) worst case | O(n) or slower |
memory safe | yes | no |
現在我們可能會看到-垃圾收集並不是一種必要的罪惡,而是我們唯一希望擁有的最好的東西。它為我們提供了安全性和性能兩者。
向C致敬
雖然 C 在我的測驗中確實顯示出較差的結果,但它仍然是一門重要的語言,並且有自己的應用領域。我的文章並不是為了拒絕或刪除 C。 C也不錯,只是沒有人們想像的那麼優越。許多好的專案失敗只是因為有些人決定使用 C 而不是 Java,例如,因為他們被告知 C 更快,而 Java 由於垃圾收集而慢得令人難以置信。當我們編寫非常小且簡單的程式時,C 很好。但是,我絕對不會建議用 C 來寫複雜的程式或遊戲。
C 不同
C 不簡單,不靈活,文法超載,規格太多複雜。使用 C 編程,你不會實現自己的想法,但 90% 的時間都會與編譯器和記憶體錯誤作鬥爭。
這篇文章的目的是拒絕C語言,因為速度和效能只是人們在軟體開發中使用這種語言的藉口。使用 C ,您要付出時間、程序表現和心理健康的代價。所以,當你在 C 和任何其他語言之間做出選擇時,我希望你選擇最後一種。
以上是C和C真的那麼快嗎?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

C#适合需要开发效率和类型安全的项目,而C 适合需要高性能和硬件控制的项目。1)C#提供垃圾回收和LINQ,适用于企业应用和Windows开发。2)C 以高性能和底层控制著称,广泛用于游戏和系统编程。

C 代碼優化可以通過以下策略實現:1.手動管理內存以優化使用;2.編寫符合編譯器優化規則的代碼;3.選擇合適的算法和數據結構;4.使用內聯函數減少調用開銷;5.應用模板元編程在編譯時優化;6.避免不必要的拷貝,使用移動語義和引用參數;7.正確使用const幫助編譯器優化;8.選擇合適的數據結構,如std::vector。

C 中的volatile關鍵字用於告知編譯器變量值可能在代碼控制之外被改變,因此不能對其進行優化。 1)它常用於讀取可能被硬件或中斷服務程序修改的變量,如傳感器狀態。 2)volatile不能保證多線程安全,應使用互斥鎖或原子操作。 3)使用volatile可能導致性能slight下降,但確保程序正確性。

在C 中測量線程性能可以使用標準庫中的計時工具、性能分析工具和自定義計時器。 1.使用庫測量執行時間。 2.使用gprof進行性能分析,步驟包括編譯時添加-pg選項、運行程序生成gmon.out文件、生成性能報告。 3.使用Valgrind的Callgrind模塊進行更詳細的分析,步驟包括運行程序生成callgrind.out文件、使用kcachegrind查看結果。 4.自定義計時器可靈活測量特定代碼段的執行時間。這些方法幫助全面了解線程性能,並優化代碼。

使用C 中的chrono庫可以讓你更加精確地控制時間和時間間隔,讓我們來探討一下這個庫的魅力所在吧。 C 的chrono庫是標準庫的一部分,它提供了一種現代化的方式來處理時間和時間間隔。對於那些曾經飽受time.h和ctime折磨的程序員來說,chrono無疑是一個福音。它不僅提高了代碼的可讀性和可維護性,還提供了更高的精度和靈活性。讓我們從基礎開始,chrono庫主要包括以下幾個關鍵組件:std::chrono::system_clock:表示系統時鐘,用於獲取當前時間。 std::chron

C 在實時操作系統(RTOS)編程中表現出色,提供了高效的執行效率和精確的時間管理。 1)C 通過直接操作硬件資源和高效的內存管理滿足RTOS的需求。 2)利用面向對象特性,C 可以設計靈活的任務調度系統。 3)C 支持高效的中斷處理,但需避免動態內存分配和異常處理以保證實時性。 4)模板編程和內聯函數有助於性能優化。 5)實際應用中,C 可用於實現高效的日誌系統。

C 中的ABI兼容性是指不同編譯器或版本生成的二進制代碼能否在不重新編譯的情況下兼容。 1.函數調用約定,2.名稱修飾,3.虛函數表佈局,4.結構體和類的佈局是主要涉及的方面。

DMA在C 中是指DirectMemoryAccess,直接內存訪問技術,允許硬件設備直接與內存進行數據傳輸,不需要CPU干預。 1)DMA操作高度依賴於硬件設備和驅動程序,實現方式因係統而異。 2)直接訪問內存可能帶來安全風險,需確保代碼的正確性和安全性。 3)DMA可提高性能,但使用不當可能導致系統性能下降。通過實踐和學習,可以掌握DMA的使用技巧,在高速數據傳輸和實時信號處理等場景中發揮其最大效能。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3漢化版
中文版,非常好用

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。