驚到了!大神炮轟CUDA:CUDA存致命缺陷,它不是未來!

編輯 | 雲昭

出品 | 51CTO技術棧(微信號:blog51cto)

CUDA一直被視爲英偉達GPU的最強壁壘,讓許多業界的玩家望洋興嘆。

但,今天這篇文章會給各位習慣C++、CUDA開發的大佬提個醒:

有一種新的編程語言,正在AI圈興起,撬動英偉達的圍牆花園。而CUDA也不再是護城河。

近日,一位大牛 Thomas Cherickal,發表了一篇博客,闡述了一種新的編程範式。

他認爲,基於 MLIR 的 Mojo 無疑將取代基於 LLVM 的 CUDA,而且這種方式已經幾乎可以在其他任何芯片上運行,包括谷歌TPU、AMD、英特爾以及任何定製的AI芯片!

作者思路非常清晰,從市場競爭格局、硬件和軟件的趨勢變化兩個角度,拆解了 CUDA 的優勢和致命缺陷,並做出了論斷:CUDA 將走向終點,而 Mojo 纔是未來。篇幅較長,建議大家收藏細讀。

01、CUDA:一座看得見的圍牆花園

其實,即便 OpenAI、DeepMind 這些 AI 巨頭,其實也都曾苦 CUDA 久矣。問題是,目前還沒什麼好替代品。

自 2007 年推出以來,CUDA 一直是 GPU 編程的黃金標準。它讓開發者能夠更精細地控制 GPU,但也讓英偉達在軟硬一體的算力生態中建立了堅固的護城河:

硬件綁定:只能運行在英偉達 GPU 上,AMD 或其他芯片基本無緣;

學習門檻高:使用 C++ 風格,語法複雜,不適合初學者;

創新被封鎖:一旦你選了 CUDA,就意味着難以遷移,成本高、空間小。

從訓練模型到部署推理,CUDA 的封閉性和高門檻,讓無數開發者又愛又恨。一邊是性能無敵的 GPU,一邊是寫起來像黑魔法一樣的 CUDA。

過去,AI 公司要想跑得快,幾乎只能選英偉達。

然而,Mojo 出現了,它帶來了一種更優的方案。

01、英偉達的挑戰者越來越多,需要新的編程理念

在分析 Mojo 優勢之前,不妨先研究下,英偉達硬件的競爭者們。

到了2025年年中,情況在發生變化。IT界正在向異構化徹底轉變。由此,我們看到科技巨頭從沒有放棄推出自己的芯片。

我們看到專用硬件遍地開花:

英特爾Gaudi系列:

英特爾的Gaudi處理器專爲深度學習訓練和推理而設計,是英偉達GPU的有力競爭者。

AMD Instinct MI系列:

AMD的MI系列GPU爲高性能計算和AI工作負載而設計,是英偉達數據中心GPU的競爭者。

Groq張量流處理器(TSP):

Groq的TSP架構爲低延遲推理和高吞吐量而設計,尤其適用於大語言模型。

谷歌TPU:

谷歌的TPU是針對機器學習工作負載(尤其在谷歌雲基礎架構中)優化的定製芯片。

AWS Trainium:

AWS Trainium 是一款爲機器學習訓練而設計的芯片,具有高性能和成本效益。

除此之外,主攻定製芯片的初創公司也不在少數。而這種百花齊放的新格局需要一種新的編程理念。

03、拆解 CUDA:它究竟強大在哪裡

CUDA 的全稱是統一計算設備架構。它是英偉達的並行計算平臺和編程模型,允許開發者編寫類似 C++ 的代碼(稱爲內核),可在英偉達 GPU 上運行。

CUDA的真正優勢在於常年積累的庫生態,其成熟度可以說市面上無與倫比。這裡展示一些:

數學庫:

cuBLAS:用於基本線性代數子程序(BLAS)。

cuRAND:用於隨機數生成。

cuFFT:用於快速傅里葉變換。

cuSPARSE:用於稀疏矩陣運算。

cuTENSOR:用於張量運算。

cuSOLVER:用於稠密和稀疏直接求解器。

並行算法庫:

nvGRAPH:用於圖算法。

Thrust:用於並行算法和數據結構。

通信庫:

NVSHMEM:用於分區全局地址空間(PGAS)編程。

NCCL:用於多GPU和多節點集體通信。

深度學習庫:

cuDNN:用於深度神經網絡計算。

TensorRT:用於優化深度學習推理。

Riva:用於對話式AI。

DALI:用於深度學習的數據加載和增強。

此外,CUDA 還對硬件實現了直接底層控制,使研究人員能夠獲得最佳性能;另外,悠久的歷史造就了龐大的社區,擁有豐富的文檔和支持。

04、但,CUDA也有致命缺陷

Cherickal 認爲,CUDA 的致命缺陷就在於它的“牢籠”。

廠商鎖定:CUDA代碼只能在英偉達GPU上運行。這導致開發者和整個行業被一家收費高昂的硬件供應商牢牢束縛。這抑制了競爭,並限制了選擇最佳硬件的自由。

雙語言問題:AI和科學計算的主要瓶頸。研究人員使用Python等高級語言設計原型,因爲簡單易用、迭代速度快。但對於生產環境而言,關注性能的代碼必須完全用低級C++/CUDA重寫。這造成了痛苦且昂貴的脫節,減緩了從研究到部署的進程。

編程複雜性:CUDA功能強大,但異常複雜和冗繁。開發者被迫手動管理內存,在CPU(主機)和GPU(設備)之間傳輸數據。開發者還必須成爲硬件調度員,管理線程塊、網格和同步。這種複雜性導致學習曲線陡峭,常常導致難以察覺的bug。

05、編譯器技術:LLVM 面臨的問題

再來看編譯器方面。大家首先會想到的是 LLVM。

LLVM項目是一系列模塊化且可重用的編譯器技術。其核心是 LLVM 中間表示(IR),這是一種類似彙編的低級語言。LLVM 已成爲現代編譯器後端的標準,尤其適用於 CPU。編譯器前端(比如面向C++的Clang)將源代碼轉換成LLVM IR。然後,LLVM 後端優化該 IR,將其轉換成特定 CPU 的機器碼。這種模塊化在當時是革命性的。

然而,LLVM 是爲以 CPU 爲中心的時代設計的。對於異構硬件盛行的新時代來說,其 IR 過於低級。

它會丟失源代碼中重要的高級信息,這個問題名爲“語義鴻溝”(semantic gap)。比如說,在編譯 TensorFlow 模型時,某個運算是卷積運算的知識或信息會丟失。

LLVM IR 只能識別一組寬泛的循環和算術指令。這使得編譯器無法執行強大的、針對特定領域的優化。它不再理解程序員的高級意圖。這就是“語義鴻溝問題”的本質,而MLIR解決了這個問題。

這裡科普一下:

CUDA 的編譯流程部分藉助了 LLVM IR(NVVM),但整體還是閉源且偏向傳統的硬編碼式工具鏈;而 Mojo 則選擇原生擁抱 MLIR(一個更現代、更模塊化的 LLVM 子項目),在可擴展性與多架構適配性上更進一步。

06、MLIR:最後一塊拼圖

MLIR(Multi-Level Intermediate Representation,多級中間表示)誕生於谷歌,最初是爲了解決 TensorFlow 無法統一編譯到 CPU、GPU 和自家 TPU 的問題。

他們很快發現:LLVM 傳統的單一、底層中間表示(IR)已經無法勝任現代異構硬件的複雜需求。

MLIR 的突破點在於,它提供了一個統一的基礎架構,可以定義、組合多個不同層次的 IR。

這些可組合的 IR 被稱爲“方言(dialects)”。

你可以把 MLIR 理解爲一個“硬件通用翻譯器”,它能同時理解從高級語言語義到底層硬件細節的所有層級。每種方言都代表了一個特定領域或抽象層級:

比如,“TensorFlow 方言”中就直接包含了 tf.conv2d 這樣的卷積操作;

而“線性代數方言”則定義了 linalg.matmul 這樣的矩陣乘法。

這使得高級語義得以完整保留,而不是像傳統編譯器那樣一上來就扁平化處理。

這樣做的最大好處,就是能啓用一種更強大的編譯策略:逐步降階(progressive lowering)。

編譯器不再一口氣把高級代碼壓成底層彙編,而是像“剝洋蔥”一樣,一層層轉化:

從高級方言(如 TensorFlow)開始,執行特定領域的優化;

然後逐步“降階”,轉換爲更低層次的中間方言(如線性代數方言、內存訪問方言等);

每個中間階段都有獨立的優化策略;

最後才進入底層方言,如 LLVM IR,用於生成最終機器碼。

這種方式能儘可能長時間地保留高階語義上下文,從而帶來更精準、更有針對性的編譯優化。

因此,在高級語言和多樣化芯片架構之間,MLIR 是目前最有希望的橋樑。

它不僅解決了 “一語言綁一硬件” 的問題,還讓開發者和編譯器都可以更自由地定義優化路徑。

簡言之:

MLIR 是連接高級編程與底層芯片世界的“關鍵接口層”。

無論你是寫 AI 框架、區塊鏈虛擬機,還是芯片設計工具,MLIR 都是值得關注的底層基石。

07、最前沿的語言,爲什麼是 Mojo?

如果說 MLIR 是強大又複雜的引擎,Mojo 就是簡潔直觀的用戶界面。

2023 年 5 月,Mojo 由 LLVM 和 Swift 語言的原始架構師 Chris Lattner 創建。其設計理念遵循第一原則,旨在成爲 MLIR 時代的完美語言,是一種可在多個平臺上實現快速且可移植的 CPU+GPU 代碼的編程語言。

就這一點而言,可以說,Mojo 是當今技術最先進的語言。

因爲,即便是近幾年大熱的 Rust,也都是基於 LLVM 的,所以具有 LLVM 的所有缺點。而 Mojo 則是當今唯一基於 MLIR 的主流編程語言。

Mojo 的主要功能有以下幾個:

一、Python 的超集

•Mojo 旨在與現有的Python生態系統完全兼容,這是一項殺手級功能!

•它允許開發者導入和使用任何Python庫,比如NumPy、Pandas或Matplotlib。

•它通過利用Python龐大的生態系統,完全規避了新語言面臨的“冷啓動”問題。

二、真正的系統編程特性:

•與Python不同,Mojo是一種具有強靜態類型的編譯語言。

•這消除了一大批的運行時錯誤,並實現了C++級的性能優化。

•它引入了現代內存管理概念以確保內存安全,比如所有權和借用(源自Rust),沒有垃圾收集器的開銷。

三、一流的MLIR集成:

•Mojo將MLIR的全部功能直接展現給開發者。

•程序員可以爲應用程序的大部分編寫類似Python的高級代碼。

•需要最高性能時,可以降級使用特定的MLIR方言,並編寫低級內核。

•重要的是,這一切可以在同一個文件中使用同一種語言完成。

此外,Mojo 還輕鬆解決了“雙語言問題”。

08、代碼PK:Mojo如何秒殺CUDA

理論是一回事,實踐是另一回事。以下完整且實用的代碼示例,將展示兩種範式之間的重大差異。

篇幅原因,這裡只舉一個“矩陣乘法”的示例。

完整的CUDA實現

這是一個完整的、可編譯的CUDA矩陣乘法程序。

// Filename: matmul.cu// To compile: nvcc matmul.cu -o matmul_cuda

#include#include#include

// Helper to check for CUDA errors#define CUDA_CHECK(err) { \cudaError_t err_code = err; \if (err_code != cudaSuccess) { \std::cerr << "CUDA Error: " << cudaGetErrorString(err_code) << " at line " << __LINE__ << std::endl; \exit(EXIT_FAILURE); \} \}

// CUDA Kernel for Matrix Multiplication (Device Code)__global__ void matrixMulKernel(float* C, const float* A, const float* B, int N) {// Calculate the global row and column index of the elementint row = blockIdx.y * blockDim.y + threadIdx.y;int col = blockIdx.x * blockDim.x + threadIdx.x;

// Boundary check to avoid accessing out-of-bounds memoryif (row < N && col < N) {float p_value = 0.0f;// Each thread computes one element of the result matrix Cfor (int k = 0; k < N; ++k) {p_value += A[row * N + k] * B[k * N + col];}C[row * N + col] = p_value;}}

// Main function (Host Code)int main() {constint N = 256;constint size = N * N * sizeof(float);

// Step 1. Allocate host memorystd::vector h_A(N * N);std::vector h_B(N * N);std::vector h_C(N * N);

// Initialize host matricesfor (int i = 0; i < N * N; ++i) {h_A[i] = static_cast(rand()) / RAND_MAX;h_B[i] = static_cast(rand()) / RAND_MAX;}

// Step 2. Allocate device memoryfloat *d_A, *d_B, *d_C;CUDA_CHECK(cudaMalloc((void**)&d_A, size));CUDA_CHECK(cudaMalloc((void**)&d_B, size));CUDA_CHECK(cudaMalloc((void**)&d_C, size));

// Step 3. Copy matrices from host to devicestd::cout << "Copying data from host to device..." << std::endl;CUDA_CHECK(cudaMemcpy(d_A, h_A.data(), size, cudaMemcpyHostToDevice));CUDA_CHECK(cudaMemcpy(d_B, h_B.data(), size, cudaMemcpyHostToDevice));

// Step 4. Define kernel launch configuration// Use 16x16 threads per block, a common choicedim3 threadsPerBlock(16, 16);// Calculate the number of blocks needed in each dimensiondim3 numBlocks((N + threadsPerBlock.x - 1) / threadsPerBlock.x, (N + threadsPerBlock.y - 1) / threadsPerBlock.y);

// Step 5. Launch the kernel on the devicestd::cout << "Launching kernel..." << std::endl;matrixMulKernel<<>>(d_C, d_A, d_B, N);CUDA_CHECK(cudaGetLastError());CUDA_CHECK(cudaDeviceSynchronize()); // Wait for the kernel to finish

// Step 6. Copy the result matrix back from device to hoststd::cout << "Copying result from device to host..." << std::endl;CUDA_CHECK(cudaMemcpy(h_C.data(), d_C, size, cudaMemcpyDeviceToHost));

// Step 7. Free device memoryCUDA_CHECK(cudaFree(d_A));CUDA_CHECK(cudaFree(d_B));CUDA_CHECK(cudaFree(d_C));

std::cout << "CUDA Matrix Multiplication finished successfully." << std::endl;// (Optional: Add verification step here)

return0;}

CUDA代碼分析:

代碼主要由樣板代碼和低級管理組成。步驟1、2、3、6和7 純粹用於跨CPU/GPU邊界管理內存。這很繁瑣,容易出錯,並掩蓋核心算法。全局關鍵字、blockIdx、threadIdx和<<<...>>>語法是CUDA特有的硬件抽象。

該代碼根本上永久地與英偉達的硬件架構緊密相關。實際算法:三個嵌套循環只佔總代碼的一小部分。程序員的精力耗費在了硬件管理上,而不是問題本身上。

完整的Mojo實現

Mojo 版本以驚人的簡潔性和強大功能實現了相同的效果。

# Filename: matmul.mojo# To run: mojo matmul.mojo

from memory import DType, Tensorfrom random import randfrom time import now

fn matmul_naive(C: Tensor[DType.float32], A: Tensor[DType.float32], B: Tensor[DType.float32]):"""A naive, high-level implementation of matrix multiplication."""let N = A.dim(0)let M = A.dim(1)let P = B.dim(1)

for i in range(N):for j in range(P):var sum: Float32 = 0.0for k in range(M):sum += A.load(i, k) * B.load(k, j)C.store(i, j, sum)

fn main():let N = 256

# 1. Allocate and initialize tensors.# Mojo's Tensor handles memory allocation automatically.# The compiler will place it in the most appropriate memory space.var A = Tensor[DType.float32](N, N)var B = Tensor[DType.float32](N, N)var C = Tensor[DType.float32](N, N)

for i in range(N):for j in range(N):A.store(i, j, rand[DType.float32]())B.store(i, j, rand[DType.float32]())

print("Starting Mojo Matrix Multiplication...")

let start_time = now()

# 2. Call the function.# The MLIR-based compiler optimizes this high-level code.# It can automatically tile, vectorize, and parallelize this code# for the target hardware (CPU, GPU, etc.).matmul_naive(C, A, B)

let end_time = now()let duration_ms = (end_time - start_time) / 1_000_000.0

print("Mojo Matrix Multiplication finished successfully.")print("Execution time:", duration_ms, "ms")# (Optional: Print a corner of the result matrix to verify)print("Result C[0,0]:", C.load(0,0))}

就是這樣!Mojo方法出色得多。

首先是,可編程性和專注性:

•Mojo代碼簡潔明瞭,直接表達算法。

•程序員專注於“什麼”(數學運算),而不是“如何”(內存傳輸)。

•無需手動執行cudaMalloc、cudaMemcpy 或 cudaFree。

•這類錯誤全部消失。

其次,它注重性能的抽象:

•執行的不是簡單的嵌套循環。

•基於MLIR的編譯器可以執行復雜的轉換。

•這將這段簡單代碼轉換成高度優化的內核。

•它可以自動運用平鋪、矢量化和並行化。

•程序員可以添加提示(比如@vectorize或@parallelize)以指導編譯器,實現控制,而無需增加複雜性。

最重要的是,終極優勢:可移植性。這是關鍵點。

•同一個matmul.mojo文件可以重新編譯,以便在英偉達GPU、AMD GPU、搭載AVX512 的英特爾CPU或谷歌TPU上運行。

•邏輯保持不變;編譯器後端發生變化。

•CUDA 代碼需要針對每個新的硬件目標進行全面且昂貴的重寫。

•Mojo 提供“性能可移植性”,打破了廠商鎖定,使代碼適應未來需要。

所以長期看,基於 MLIR 的 Mojo 無疑將取代基於 LLVM 的 CUDA(部分基於),開發者將享受這一變化!

09、Mojo重新定義了遊戲規則

爲什麼這麼說?

一、職責分離,思維方式的顛覆

Mojo 與 CUDA 的最大區別,在於它們對“程序員該關心什麼”的定義截然不同:

Mojo 代碼:專注於算法本身開發者只需表達“我要做什麼”,即模型的計算邏輯和結構;

CUDA 代碼:專注於硬件實現開發者需要手動指定線程分佈、內存佈局等 GPU 底層細節。

這種區別不是小修小補,而是編程範式的根本轉變。在 Mojo 中,開發者可以把精力放在如何改進算法上;而具體“怎麼映射到芯片上”,交給 MLIR 編譯器自動完成。

二、更快的研究週期、更低的心智負擔

在 AI 研究中,嘗試一個新模型結構或優化一個訓練技巧,是日常操作。

用 Mojo 寫的模型邏輯清晰、可讀性強,研究人員可以輕鬆修改並快速驗證想法;

相比之下,CUDA 的底層代碼常常需要大量位運算、手動調度線程、控制內存訪問——動一下都像拆引擎蓋改引擎,又慢又容易出錯。

這意味着:Mojo 能大幅加速 AI 的研發週期,真正做到“想法立刻變成實驗”。

三、最關鍵的:硬件自由

Mojo 寫出來的代碼不是專屬於 NVIDIA 的!通過 MLIR 的多級中間表示,Mojo 代碼可以編譯運行在多種硬件上:

AMD GPU

Google TPU

Intel Gaudi

各類定製 AI 加速芯片(如 AI Startup 的專用 ASIC)

甚至只要定義新的“方言”,未來任何新架構都能支持。

這意味着:

Mojo 代碼是“面向未來”的,不被任何一家芯片廠商鎖死。

這也是打破英偉達壟斷、推動算力成本下降的關鍵一環。

10、最終:CUDA的終點,Mojo的未來

當我們將目光從當下主流的密集矩陣運算,轉向未來更廣闊的計算領域時,CUDA 的侷限就開始暴露。而 MLIR + Mojo 的組合,正是爲這種異構、多樣、併發、稀疏甚至非傳統的計算範式而生。

作者舉了一個算力進化的例子:區塊鏈。

比特幣這類工作量證明(PoW)機制的區塊鏈,需要巨大的哈希運算能力。

目標是找到一個“nonce”(隨機數),使其與區塊數據一起哈希後的結果小於目標值——這完全是暴力窮舉搜索,最適合並行加速硬件。

起初人們用 CPU;

後來轉向並行能力更強的 GPU;

再後來,進入ASIC(專用集成電路)時代。

比如:SHA-256 的 ASIC,把哈希算法直接寫入了硅片,能效比 GPU 高出幾個數量級。

這就是 CUDA 的終點。但 Mojo 和 MLIR 的故事纔剛開始。

MLIR + Mojo 如何改變芯片設計呢?

芯片設計領域有個術語叫HLS(高階綜合):把高級算法描述轉成硬件電路語言(如 Verilog 或 VHDL)並燒錄進芯片。

MLIR,藉助項目如 CIRCT(專爲硬件設計的 MLIR 子項目),正是下一代 HLS 的核心支撐。

一段 Mojo 寫的哈希算法代碼,可以編譯爲:

GPU 上運行的並行程序(通過 GPU 後端);

或直接轉爲 Verilog,用於設計專屬 ASIC 芯片。

同一段 Mojo 代碼,同時通往軟件和硬件的兩個世界。

這就是 MLIR 帶來的“從軟件到硅”的編譯能力 —— CUDA 無法涉足的疆域。

寫在最後:Mojo會是贏家嗎

一方面,未來是異構芯片的天下,這並非猜測,而是事實。廠商鎖定所帶來的商業和技術風險不可接受。

另一方面,隨着時間演進,如今 GPU 僵硬的 SIMT 模式不再適應稀疏數據、神經形態AI、區塊鏈和量子計算的發展趨勢。

而 MLIR 是目前唯一一種旨在解決這個問題且得到業界支持的架構。

同時,谷歌、蘋果、英特爾、AMD 和 ARM 紛紛採用,清晰地表明瞭其在未來編譯器領域的核心地位。

而, Mojo 恰恰是迄今唯一能夠駕馭這種強大功能的語言。

Mojo解決了雙語言問題,兼具易用性和性能,並提供了通往整個 MLIR 生態系統的門戶。

因此,從 CUDA 到基於 MLIR 的世界的過渡將是漸進的過程,卻又是不可避免的。這是從以硬件爲中心的封閉模式向軟件定義的開放未來的根本性轉變。

但從長遠來看,Mojo 會是贏家嗎?Mojo 弱勢在於生態還沒有成熟。

但目前看,至少開發者會更喜歡 Mojo,而不是 CUDA。

這篇懟CUDA的文章終於結束了,老規矩,大佬們怎麼看?歡迎評論區交流。

https://hackernoon.com/this-new-language-might-kill-nvidias-gpu-monopoly

https://hackernoon.com/meet-mojo-the-language-that-could-replace-python-c-and-cuda?embedable=true