選擇后端編程語言絕非易事。畢竟不同的語言各有優(yōu)缺點(diǎn),我們需要考慮它是否是構(gòu)建應(yīng)用程序的正確工具。
Node.js 和 Python 是后端開發(fā)的兩個(gè)最受歡迎的選擇。兩者都有非常強(qiáng)大的包裝生態(tài)系統(tǒng)和社區(qū),在兩者之間進(jìn)行選擇可能比較困難。
在本文中,我們將分析 Node.js 和 Python 的優(yōu)缺點(diǎn),并分析其中一個(gè)比另一個(gè)更好的場景,以便大家可以為自己的后端做出最佳選擇。
我們將涵蓋以下主題:
- 什么是 Node.js?
- 什么是 Python?
- 比較架構(gòu)
- 并發(fā)和并行
什么是 Node.js?
Node.js 是在 Google 的 V8 引擎上運(yùn)行的異步 JavaScript 運(yùn)行時(shí)。它通常用于構(gòu)建實(shí)時(shí)應(yīng)用程序、后端以及桌面和移動(dòng)應(yīng)用程序。
Node.js 是多范式的,支持以下范式:
- 事件驅(qū)動(dòng)
- 至關(guān)重要的
- 面向?qū)ο?/li>
- 函數(shù)式編程
Node 由 Ryan Dahl 開發(fā)并于 2009 年發(fā)布,一炮而紅,因?yàn)樗状卧试S JavaScript 開發(fā)人員在 Web 瀏覽器之外編寫 JavaScript 代碼。多年來,它已經(jīng)成長并成為 Python 等老語言的有力競爭者,并提供了一系列后端開發(fā)工具,如Express.js、Fastify 和 NestJS。
什么是 Python?
Python 是一種解釋型通用編程語言,通常用于腳本編寫、后端開發(fā)、機(jī)器學(xué)習(xí)和數(shù)據(jù)科學(xué)等。它支持多種范式,例如:
- 程序
- 面向?qū)ο?/li>
- 函數(shù)式編程
它由 Guido van Rossum 設(shè)計(jì)和開發(fā),并于 1991 年發(fā)布并獲得了主流成功;Python 一直位居TIOBE 編程社區(qū)指數(shù)的前 10 名。除此之外,谷歌、Facebook、Dropbox 和 Instagram 等大公司都將它用于內(nèi)部和外部工具——甚至 NASA 也找到了它的應(yīng)用程序。
Python 在不斷發(fā)展,它擁有成熟的 Web 框架,例如Django、Flask和FastAPI,你也可以在后端開發(fā)項(xiàng)目中使用這些框架。
比較架構(gòu)
軟件架構(gòu)描述了系統(tǒng)中的主要組件如何交互、關(guān)聯(lián)和組織。良好的架構(gòu)設(shè)計(jì)可以使系統(tǒng)具有可擴(kuò)展性、性能良好和可維護(hù)性。
在本節(jié)中,我們將鳥瞰 Node.js 和 Python 架構(gòu)。
Node.js
Node.js 是單線程、非阻塞的,并且實(shí)現(xiàn)了事件驅(qū)動(dòng)的架構(gòu)。它有一個(gè)線程,你編寫的所有代碼和你使用的庫都在其中執(zhí)行。它還利用libuv C 庫提供的其他線程來處理昂貴或長時(shí)間運(yùn)行的任務(wù)。
Node.js 使用回調(diào)來表示長時(shí)間運(yùn)行的任務(wù)完成,一旦完成,它們會(huì)被添加到任務(wù)隊(duì)列中,然后最終被添加回主線程。這種行為是 Node.js 非阻塞的原因,因?yàn)榘嘿F的任務(wù)不會(huì)阻塞主線程;相反,它們在單獨(dú)的 libuv 線程中執(zhí)行,并且 Node.js 繼續(xù)執(zhí)行源代碼的其他部分。
Python
Python 也是一種單線程語言,主要是因?yàn)樗鼘?shí)現(xiàn)了全局解釋器鎖 (GIL),這是一種僅允許一個(gè)線程控制 Python 解釋器并在給定時(shí)間運(yùn)行 Python 代碼的機(jī)制。即使 Python 程序使用多個(gè)線程,GIL 也會(huì)定期在線程之間切換,讓每個(gè)線程都有機(jī)會(huì)執(zhí)行代碼——但默認(rèn)情況下它們不能并行執(zhí)行。這種行為使 Python 成為單線程的。
與 Node.js 不同,Python 不是基于事件驅(qū)動(dòng)的架構(gòu)。但是,你仍然可以使用asyncio 包來利用它,它允許你使用 async/await 語法編寫異步代碼,因?yàn)樗鼘?shí)現(xiàn)了事件循環(huán)、期貨等。
判決
盡管語言的架構(gòu)不同,但兩種語言都是不錯(cuò)的選擇,并且可以支持同步和異步編程。
并發(fā)和并行
選擇后端的另一個(gè)重要方面是并發(fā)性和并行性。這些術(shù)語往往會(huì)使人們感到困惑,所以讓我們定義它們,以便我們可以在同一頁面上:
- 并發(fā):兩個(gè)或多個(gè)任務(wù)在多個(gè)線程中執(zhí)行,但不是同時(shí)執(zhí)行。相反,執(zhí)行在任務(wù)之間切換,當(dāng)計(jì)算機(jī)中斷一個(gè)任務(wù)切換到另一個(gè)任務(wù)時(shí),它可以從中斷點(diǎn)繼續(xù)執(zhí)行另一個(gè)任務(wù)
- 并行:當(dāng)多個(gè)任務(wù)同時(shí)在不同的線程中執(zhí)行時(shí)
當(dāng)你的應(yīng)用程序任務(wù)受 CPU 限制時(shí),并發(fā)性和并行性非常寶貴,例如在以下任務(wù)中:
- 處理圖像
- 加密
- 進(jìn)行復(fù)雜的計(jì)算
- 視頻壓縮
如果你想提高這些任務(wù)的性能,你可以將它們拆分到不同的線程中并行執(zhí)行。
有了這個(gè),現(xiàn)在讓我們看看 Node 和 Python 如何處理并發(fā)和并行性。
Node.js
即使 Node 是單線程的,你也可以使用worker_threads模塊編寫多線程程序。該模塊創(chuàng)建輕量級線程工作者,允許你并行執(zhí)行 CPU 密集型 JavaScript 代碼。
工作線程與主線程(父線程)共享相同的內(nèi)存和進(jìn)程ID,線程之間通過消息傳遞進(jìn)行通信。你可以在博客的其他地方了解有關(guān)如何在 Node.js 中編寫多線程程序的更多信息。
Python
在 Python 中,你可以使用threading 模塊實(shí)現(xiàn)并發(fā),該模塊創(chuàng)建線程來執(zhí)行部分代碼。但是,這并不意味著線程將并行執(zhí)行。這是因?yàn)?GIL,它確保只有一個(gè)線程可以執(zhí)行 Python 代碼,并定期在它們之間切換。
雖然并發(fā)對 I/O 密集型任務(wù)很有幫助,但 CPU 密集型任務(wù)從并行性中受益匪淺。為了實(shí)現(xiàn)并行性,Python 提供了多處理模塊,該模塊在每個(gè)內(nèi)核上創(chuàng)建一個(gè)進(jìn)程,并允許你利用多核系統(tǒng)并行執(zhí)行 Python 代碼。
每個(gè)進(jìn)程都有自己的解釋器和 GIL,但它確實(shí)有一些注意事項(xiàng)。一方面,與工作線程相比,進(jìn)程的通信有限,另一方面,啟動(dòng)進(jìn)程往往比啟動(dòng)線程更昂貴。
判決
Python的threading模塊與Node.jsworker_thread模塊相比相形見絀,后者可以輕松實(shí)現(xiàn)并發(fā)和并行。Node.js 之所以獲勝,是因?yàn)樗С植l(fā)和并行性,而不需要像 Python 那樣的變通方法。
性能和速度
更快的后端可以減少你的服務(wù)器響應(yīng)時(shí)間,從而提高頁面速度。良好的頁面速度可以幫助你的 Web 應(yīng)用程序在 Google 上獲得良好的排名,并為你的用戶提供良好的體驗(yàn)。
編程語言的速度往往與源代碼的執(zhí)行方式密切相關(guān)。讓我們探討一下 Node.js 和 Python 在執(zhí)行期間如何比較,以及它如何影響它們各自的執(zhí)行速度。
Node.js
Node 以快速執(zhí)行代碼而聞名,其中大部分可以歸結(jié)為幾個(gè)原因。
首先,如前所述,Node.js 被編譯為機(jī)器碼并建立在 Google V8 引擎之上,這是一個(gè)用 C++ 編寫的高性能 JavaScript 引擎。V8 引擎將你的 JavaScript 編譯為機(jī)器代碼,因此 CPU 直接執(zhí)行它,從而為你提供快速的性能。Node.js 還從 Google 對 V8 引擎的頻繁性能更新中受益匪淺。
其次,Node.js 是非阻塞的,并且建立在事件驅(qū)動(dòng)的架構(gòu)之上。它對 Node.js 中的幾乎每個(gè) I/O 方法操作都有異步方法。由于 Node.js 是單線程的,如果一個(gè)操作耗時(shí)較長,它不會(huì)阻塞主線程。相反,它并行執(zhí)行它,為代碼的其他部分提供執(zhí)行空間。
Python
Python 的執(zhí)行速度比 Node 慢很多。有幾個(gè)因素會(huì)影響 Python 的速度。對于初學(xué)者,Python 會(huì)自動(dòng)將源代碼編譯成字節(jié)碼,這是一種只有 Python 虛擬機(jī) (PVM) 才能解釋的低級格式。這會(huì)影響性能,因?yàn)?CPU 不直接執(zhí)行字節(jié)碼,而是由 PVM 解釋代碼,這會(huì)減慢執(zhí)行時(shí)間。
作為該問題的解決方案,Python 有替代實(shí)現(xiàn),例如PyPy,它聲稱通過使用即時(shí) (JIT)比默認(rèn)的 Python 實(shí)現(xiàn)快 4.5 倍。如果你的 Python 應(yīng)用程序迫切需要速度,那么你應(yīng)該考慮使用 PyPy。
話雖如此,雖然 Python 比 Node.js 慢,但它的速度對于很多項(xiàng)目來說仍然足夠好,這就是它仍然受歡迎的原因。
判決
Node.js 是贏家,因?yàn)樗膱?zhí)行速度與編譯成機(jī)器代碼的速度一樣快,而 Python 是用 PVM 解釋的,這個(gè)過程往往會(huì)減慢執(zhí)行速度。
可擴(kuò)展性
當(dāng)應(yīng)用程序受到關(guān)注時(shí),會(huì)發(fā)生以下情況:
- 由于用戶數(shù)量增加,客戶請求增加
- 需要處理的數(shù)據(jù)量增加
- 新功能介紹
應(yīng)用程序在不損失性能的情況下因需求增加而增長和調(diào)整的能力稱為擴(kuò)展。
Node.js
Node.js 提供了一個(gè)原生集群模塊,讓你無需額外的努力即可擴(kuò)展你的應(yīng)用程序。該模塊在多核系統(tǒng)中的每個(gè)核上創(chuàng)建一個(gè)單獨(dú)的進(jìn)程或工作程序。每個(gè)工作人員都有一個(gè)應(yīng)用程序?qū)嵗耗K有一個(gè)內(nèi)置的負(fù)載均衡器,它使用循環(huán)算法將傳入的請求分配給所有工作人員。
Node.js 也可以很好地?cái)U(kuò)展,因?yàn)樗褂酶俚木€程來處理客戶端請求。結(jié)果,它將大部分資源用于服務(wù)客戶端,而不是處理可能昂貴的線程生命周期開銷。
Python
Python 沒有 Node.js 的集群模塊的原生等價(jià)物。最接近的是多處理模塊,它可以在每個(gè)核心上創(chuàng)建進(jìn)程,但它缺少一些集群功能。做集群計(jì)算,可以使用第三方包如:
- 芹菜
- 儀表板
- 水壺
Python wiki有一個(gè) Python 集群計(jì)算包的完整列表。
判決
與 Python 相比,Node.js 集群模塊允許 Node 應(yīng)用程序更容易擴(kuò)展。然而,重要的是要承認(rèn)現(xiàn)在大多數(shù)人都在使用 Docker 進(jìn)行擴(kuò)展。
使用 Docker,你可以創(chuàng)建多個(gè)容器,其中每個(gè)容器都包含一個(gè)應(yīng)用程序?qū)嵗?。你可以?chuàng)建與系統(tǒng)上可用的內(nèi)核一樣多的容器,并在每個(gè)容器中放置一個(gè)負(fù)載均衡器來分發(fā)請求。因此,無論你使用 Python 還是 Node.js,都可以使用 Docker 來簡化擴(kuò)展。
可擴(kuò)展性
并非每種編程語言都可以有效地解決你遇到的每個(gè)問題,有時(shí)你需要使用另一種可以擅長手頭任務(wù)的編程語言進(jìn)行擴(kuò)展。
讓我們探索 Node.js 和 Python 的可擴(kuò)展性。
Node.js
你可以通過使用addons使用C/C++ 擴(kuò)展 Node.js。例如,C++ 插件允許你編寫 C++ 程序,然后使用該require方法將其加載到你的 Node.js 程序中。借助此功能,你可以利用 C++ 庫、速度或線程。
要實(shí)現(xiàn)插件,你可以使用:
- 節(jié)點(diǎn) API
- Node.js 的本機(jī)抽象
你還可以使用 Rust 擴(kuò)展 Node.js;查看本教程以了解如何操作。
Python
Python 還具有良好的語言擴(kuò)展能力。你可以使用 C 或 C++ 對其進(jìn)行擴(kuò)展,這允許你在 Python 中調(diào)用 C/C++ 庫,或者在 C/C++ 中調(diào)用 Python 代碼。
你還可以使用替代 Python 實(shí)現(xiàn)來擴(kuò)展 Python,其中包括:
- Jython:使與 Java 的集成更容易
- IronPython:允許 Python 與 Microsoft 的 .NET 框架順利集成
判決
兩者都很好地支持用其他語言擴(kuò)展它們。
靜態(tài)類型
Node.js 和 Python 都是動(dòng)態(tài)類型語言,它們允許你快速編程,而無需為你編寫的代碼定義類型。但是,隨著代碼庫的增長,需要靜態(tài)類型來幫助你及早發(fā)現(xiàn)錯(cuò)誤,并記錄你的代碼以供將來參考。盡管 Python 和 Node.js 是動(dòng)態(tài)類型的,但它們都提供了靜態(tài)類型工具,如果需要,你可以在代碼庫中使用這些工具。
Node.js
Node.js 作為 JavaScript 生態(tài)系統(tǒng)的一部分,擁有TypeScript,它是微軟于 2012 年開發(fā)的 JavaScript 的強(qiáng)類型超集。TypeScript 支持漸進(jìn)類型,這意味著即使沒有類型,你也可以使用 TypeScript,并根據(jù)需要添加它們。
當(dāng)你使用 TypeScript 時(shí),你將源代碼保存在擴(kuò)展而不是擴(kuò)展中,并且它涉及將所有 TypeScript 文件編譯為 JavaScript 的構(gòu)建步驟。由于 TypeScript 是一種獨(dú)立于 Node 的語言,因此它的發(fā)展速度要快得多,并且你可以使用所有更新的功能,因?yàn)樗鼈兛偸潜痪幾g為 JavaScript。.ts.js
近年來,TypeScript 越來越受歡迎,從長遠(yuǎn)來看,它在 npm 上的每周下載量超過 2900 萬次。根據(jù) Stack Overflow 2021 開發(fā)者調(diào)查,它被評為第三大最受歡迎的編程語言,超過了 Python、Node.js 和 JavaScript 本身。要了解如何使用節(jié)點(diǎn)設(shè)置 TypeScript,請參閱這篇文章。
Python
與 Node.js 不同,Python 不需要單獨(dú)的類型語言。相反,它帶有可以在項(xiàng)目中使用的類型提示。但是,Python 不會(huì)自行執(zhí)行靜態(tài)類型分析;相反,你使用mypy 之類的工具進(jìn)行靜態(tài)類型檢查。如果你想了解如何在 Python 中進(jìn)行靜態(tài)類型檢查,請參閱這篇文章。
Python 的類型提示方法的優(yōu)點(diǎn)是你不必為源代碼使用不同的文件擴(kuò)展名并將其編譯為 Python 文件擴(kuò)展名。但缺點(diǎn)是每個(gè)新的 Python 版本都會(huì)引入更新的類型提示,每個(gè)版本大約需要一年時(shí)間。另一方面,TypeScript 的發(fā)布時(shí)間表為 3-4 個(gè)月。
判決
Node.js 之所以獲勝,是因?yàn)?TypeScript 的發(fā)展速度比 Python 快得多。但是,承認(rèn) Python 無需其他語言即可添加類型的能力也很好。
社區(qū)和圖書館
社區(qū)在軟件開發(fā)中扮演著重要角色。具有大型社區(qū)的編程語言往往具有:
- 更多用于開發(fā)的庫和工具
- 更多學(xué)習(xí)內(nèi)容
- 更容易找到支持
- 更容易找到出租的開發(fā)商
Node.js 和 Python 同樣擁有強(qiáng)大的社區(qū),但讓我們仔細(xì)看看它們中的每一個(gè)。
Node.js
Node.js 擁有一個(gè)強(qiáng)大而活躍的社區(qū),該社區(qū)已經(jīng)構(gòu)建了超過一百萬個(gè)開源包,所有這些都可以在 npm 上提供給你。
以下是你可能會(huì)遇到的一些軟件包:
- Express:用于構(gòu)建 Web 應(yīng)用程序的 Web 框架
- Axios : 用于發(fā)出 API 請求
- Lodash:一個(gè)實(shí)用程序庫
要發(fā)現(xiàn)更多包,可以參閱 GitHub 上精選的 awesome-nodejs 存儲庫。
除了軟件包,Node.js 有大量高質(zhì)量的書面內(nèi)容,視頻教程分布在許多平臺上,包括這個(gè)博客。這使得學(xué)習(xí) Node.js 變得更加容易,當(dāng)你被困在一個(gè)任務(wù)上時(shí),更有可能有人在你之前在 Stack Overflow 等問答平臺上問過這個(gè)問題。
此外,Node.js 還有很多國際會(huì)議,你可以在其中了解更多關(guān)于 Node.js 并結(jié)識其他人,以及專注于 Node.js 的在線社區(qū)。
Python
Python 還擁有一個(gè)活躍的社區(qū),在Python 包索引上擁有超過 37 萬個(gè)包和 340 萬個(gè)版本。你可以使用pip將它們下載到你的項(xiàng)目中,這是一個(gè)從 Python 包索引中提取包的包安裝程序。
以下是一些流行的軟件包:
- NumPy:一個(gè)處理數(shù)組的庫
- Pandas:用于分析數(shù)據(jù)
- Django:一個(gè)網(wǎng)絡(luò)框架
有關(guān)完整列表,請參閱awesome-python GitHub 存儲庫。
與 Node.js 一樣,Python 擁有大量視頻和書面內(nèi)容,以及活躍的在線社區(qū),以及在 40 多個(gè)國家/地區(qū)舉行的Python 會(huì)議 (PyCon)等會(huì)議。
判決
他們都在這里獲勝,因?yàn)?Node 和 Python 都擁有高質(zhì)量的內(nèi)容、活躍的社區(qū)以及大量用于開發(fā)的包。
常見用例
Python 和 Node.js 各有優(yōu)缺點(diǎn),我們在此進(jìn)行了深入介紹。由于 Python 的包和社區(qū),一些任務(wù)更適合 Python,而由于語言的體系結(jié)構(gòu)和其他因素,一些任務(wù)更適合 Node.js。
Node.js
由于 Node.js 的非阻塞和事件驅(qū)動(dòng)架構(gòu),它往往常用于:
- CPU 綁定操作:由于良好的多線程支持
- I/O 操作:由于非阻塞和事件驅(qū)動(dòng)的架構(gòu)
- 實(shí)時(shí)應(yīng)用程序:使用像socket.io 這樣的庫
Python
另一方面,科學(xué)界大力支持 Python,因此有許多用于機(jī)器學(xué)習(xí)、數(shù)據(jù)分析等的軟件包,例如:
- 數(shù)字貨幣
- 科學(xué)派
- Matplotlib
如果你的應(yīng)用程序更專注于數(shù)據(jù)分析或使用科學(xué)家使用的工具,那么 Python 是一個(gè)很好的選擇。
判決
兩者都很好。這主要取決于你想用它們做什么。Node.js 適用于實(shí)時(shí)應(yīng)用程序,而 Python 適用于需要數(shù)據(jù)分析和可視化的應(yīng)用程序。
結(jié)論
我們已經(jīng)到了本文的結(jié)尾。我們已經(jīng)了解了 Python 和 Node.js 之間的區(qū)別,我希望你已經(jīng)了解到?jīng)]有完美的工具。盡管如此,這些語言仍在努力解決其局限性,無論是使用內(nèi)置工具還是第三方工具。
你對后端語言的選擇很大程度上取決于你要構(gòu)建的應(yīng)用程序類型,我希望本指南可以幫助你為后端做出正確的決定。
僅200個(gè)監(jiān)控生產(chǎn)中失敗和緩慢的網(wǎng)絡(luò)請求
部署基于節(jié)點(diǎn)的 Web 應(yīng)用程序或網(wǎng)站是很容易的部分。確保你的 Node 實(shí)例繼續(xù)為你的應(yīng)用程序提供資源是事情變得更加困難的地方。如果你有興趣確保對后端或第三方服務(wù)的請求成功可以嘗試 LogRocket。
https://logrocket.com/signup/
LogRocket就像一個(gè)用于網(wǎng)絡(luò)和移動(dòng)應(yīng)用程序的 DVR,記錄用戶與你的應(yīng)用程序交互時(shí)發(fā)生的所有事情。無需猜測問題發(fā)生的原因,你可以匯總和報(bào)告有問題的網(wǎng)絡(luò)請求,以快速了解根本原因。
LogRocket 檢測你的應(yīng)用程序以記錄基準(zhǔn)性能時(shí)間,例如頁面加載時(shí)間、第一個(gè)字節(jié)的時(shí)間、緩慢的網(wǎng)絡(luò)請求,并記錄 Redux、NgRx 和 Vuex 操作/狀態(tài)。免費(fèi)開始監(jiān)控。