Porównanie wydajności języków backend GO vs Python vs Node.js
Mateusz Kędziora

Wstęp
Codziennie wielu początkujących, a czasami nawet doświadczonych programistów zadaje sobie pytanie, jakiego języka do napisania backendu użyć? Dzisiaj postaram się odpowiedzieć na to pytanie z punktu widzenia wydajności kilku z popularniejszych języków backendowych.
Przebieg badania
Badanie polegało na przeprowadzeniu szeregu testów – obliczania zadanej precyzji liczby Pi za pomocą prostego algorytmu BBP. Każdy język miał postawiony serwer WWW, który po otrzymaniu zapytania o wymaganej precyzji liczył Pi i zwracał czas wykonania skryptu.
Kod obliczania liczby Pi za pomocą Go przy użyciu BBP formula
func calculatePi(n int) *big.Float {
precision := uint(n * 14)
pi := new(big.Float).SetPrec(precision)
pi.SetInt64(0)
one := new(big.Float).SetInt64(1)
two := new(big.Float).SetInt64(2)
four := new(big.Float).SetInt64(4)
five := new(big.Float).SetInt64(5)
six := new(big.Float).SetInt64(6)
eight := new(big.Float).SetInt64(8)
sixteen := new(big.Float).SetInt64(16)
for i := 0; i < n; i++ {
k := new(big.Float).SetInt64(int64(i))
// Obliczanie 16^i
powSixteen := new(big.Float).SetInt64(1)
for j := 0; j < i; j++ {
powSixteen.Mul(powSixteen, sixteen)
}
// Obliczanie 1/16^i
denominator := new(big.Float).SetPrec(precision)
if powSixteen.Sign() != 0 {
denominator.Quo(one, powSixteen)
} else {
continue
}
// Obliczanie poszczególnych składników
term1 := new(big.Float).SetPrec(precision)
term1.Mul(eight, k)
term1.Add(term1, one)
term1.Quo(four, term1)
term2 := new(big.Float).SetPrec(precision)
term2.Mul(eight, k)
term2.Add(term2, four)
term2.Quo(two, term2)
term3 := new(big.Float).SetPrec(precision)
term3.Mul(eight, k)
term3.Add(term3, five)
term3.Quo(one, term3)
term4 := new(big.Float).SetPrec(precision)
term4.Mul(eight, k)
term4.Add(term4, six)
term4.Quo(one, term4)
// Łączenie składników
sum := new(big.Float).SetPrec(precision)
sum.Sub(term1, term2)
sum.Sub(sum, term3)
sum.Sub(sum, term4)
// Mnożenie przez 1/16^i i dodawanie do wyniku
sum.Mul(sum, denominator)
pi.Add(pi, sum)
}
return pi
}
Kod obliczania liczby Pi za pomocą Pythona przy użyciu BBP formula
from decimal import Decimal, getcontext
def calculate_pi(n):
getcontext().prec = n * 14
pi = Decimal(0)
k = Decimal(0)
x = Decimal(1)
sixteen = Decimal(16)
for i in range(n):
pi += (Decimal(4) / (8*k + 1) -
Decimal(2) / (8*k + 4) -
Decimal(1) / (8*k + 5) -
Decimal(1) / (8*k + 6)) * x
k += 1
x /= 16
return pi
Kod obliczania liczby Pi za pomocą Node.js(JavaScirpt) przy użyciu BBP formula
const Decimal = require("decimal.js");
function calculatePi(n) {
Decimal.config({ precision: n * 14 });
let pi = new Decimal(0);
let k = 0; // Using a simple integer for k
let x = new Decimal(1);
const sixteen = new Decimal(16);
for (let i = 0; i < n; i++) {
// Precompute common terms to avoid recalculating them
const denominator1 = new Decimal(8).times(k).plus(1);
const denominator2 = new Decimal(8).times(k).plus(4);
const denominator3 = new Decimal(8).times(k).plus(5);
const denominator4 = new Decimal(8).times(k).plus(6);
// Calculate the contributions to pi
const term1 = Decimal.div(4, denominator1);
const term2 = Decimal.div(2, denominator2);
const term3 = Decimal.div(1, denominator3);
const term4 = Decimal.div(1, denominator4);
// Update pi with the calculated terms
pi = pi.plus(term1.minus(term2).minus(term3).minus(term4).times(x));
// Increment k and update x
k++;
x = x.div(sixteen);
}
return pi;
}
Do tego został napisany skrypt w JavaScript, który miał za zadanie wykonywać po kolei zapytania do backendów.
Całość kodu użytego przy testach dla wszystkich języków dostępna jest tutaj.
Środowisko testowe
Testy zostały przeprowadzone na komputerze testowym wyposażonym w procesor Intel Core i3-10100 wspierany przez 16Gb pamięci ram. Urządzenie działa pod kontrolą GNU/Linux.
Wersje języków i pakietów użyte przy testach:
- Golang - go version go1.23.2 linux/amd64
- Python - Python 3.10.12
- Node.js - v20.18.0
Opis języków i frameworków
- Go, stworzony przez inżynierów Google, to język programowania statycznie typowany, kompilowany, znany ze swojej prostoty i wydajności. Jego składnia jest minimalistyczna, co przyspiesza zarówno pisanie, jak i czytanie kodu. Go jest szczególnie dobrze przystosowany do tworzenia aplikacji sieciowych, które muszą obsługiwać duże obciążenia. Dzięki swojej wydajności, niskiemu zużyciu zasobów i możliwościach współbieżności, Go stał się popularnym wyborem dla backendów wymagających szybkiej odpowiedzi i skalowalności.
- Flask, choć często mylnie utożsamiany z językiem programowania, jest lekkim frameworkiem webowym opartym na języku Python. Jego minimalistyczne podejście i elastyczność sprawiają, że jest doskonałym wyborem dla projektów o różnej skali. Python, znany z czytelnej składni, nadaje Flasku przewagę w zakresie szybkiego prototypowania i rozwoju. Choć nie jest tak szybki jak Go, Flask, dzięki optymalizacji i wykorzystaniu odpowiednich bibliotek, może osiągać zaskakująco dobre wyniki wydajnościowe, szczególnie w przypadku mniejszych aplikacji i API.
- Node.js to środowisko runtime oparte na języku JavaScript, które zrewolucjonizowało sposób tworzenia aplikacji webowych po stronie serwera. Jego architektura oparta na pętli zdarzeń (event loop) umożliwia wydajne obsługę wielu połączeń jednocześnie, co czyni go idealnym wyborem dla aplikacji wymagających dużej skalowalności i responsywności. Node.js odznacza się lekką wagą i prostotą, co przyspiesza proces rozwoju. Znajduje szerokie zastosowanie w tworzeniu aplikacji real-time, takich jak czaty, gry online czy aplikacje IoT. Dzięki dużej społeczności i bogatemu ekosystemowi pakietów NPM, Node.js oferuje niezliczone możliwości rozszerzenia funkcjonalności aplikacji.
Wyniki testów
Wyniki w formie tabelarycznej
Precyzja: 100
Język | Średni czas (ms) | Mediana (ms) | Min (ms) | Max (ms) |
---|---|---|---|---|
Go | 0.675 | 0.690 | 0.582 | 0.797 |
Python | 1.673 | 1.697 | 1.517 | 1.771 |
Node.js | 8.671 | 8.737 | 7.760 | 9.605 |
Precyzja: 500
Język | Średni czas (ms) | Mediana (ms) | Min (ms) | Max (ms) |
---|---|---|---|---|
Go | 12.021 | 12.315 | 11.361 | 16.159 |
Python | 58.813 | 58.623 | 57.752 | 60.038 |
Node.js | 599.401 | 601.134 | 585.441 | 610.239 |
Precyzja: 1000
Język | Średni czas (ms) | Mediana (ms) | Min (ms) | Max (ms) |
---|---|---|---|---|
Go | 45.114 | 45.289 | 42.273 | 49.646 |
Python | 343.353 | 344.702 | 342.768 | 345.834 |
Node.js | 4365.629 | 4354.201 | 4328.246 | 4417.671 |
Precyzja: 1500
Język | Średni czas (ms) | Mediana (ms) | Min (ms) | Max (ms) |
---|---|---|---|---|
Go | 108.187 | 107.970 | 98.775 | 117.946 |
Python | 1063.654 | 1059.157 | 1047.531 | 1066.307 |
Node.js | 14280.669 | 14276.412 | 14258.188 | 14310.617 |
Precyzja: 2000
Język | Średni czas (ms) | Mediana (ms) | Min (ms) | Max (ms) |
---|---|---|---|---|
Go | 186.828 | 176.861 | 176.797 | 210.801 |
Python | 2088.185 | 2087.251 | 2085.575 | 2092.221 |
Node.js | 33577.743 | 33573.960 | 33474.160 | 33615.152 |
Precyzja: 2500
Język | Średni czas (ms) | Mediana (ms) | Min (ms) | Max (ms) |
---|---|---|---|---|
Go | 290.621 | 286.428 | 283.795 | 298.840 |
Python | 3619.566 | 3610.895 | 3609.452 | 3634.539 |
Node.js | 65183.967 | 65148.349 | 65012.797 | 65316.498 |
Wykres zależności precyzji od czasu wykonania

Analiza wyników
W przeprowadzonych testach wydajności, Go okazało się zdecydowanym zwycięzcą, konsekwentnie, osiągając najkrótsze czasy obliczeń dla wszystkich poziomów precyzji. Python, choć również sprawdził się dobrze przy niższych poziomach precyzji, znacząco zwolnił wraz ze wzrostem złożoności obliczeń. Node. Js, z kolei, wypadł najgorzej, demonstrując wyraźne pogorszenie wydajności przy większej liczbie miejsc po przecinku. Te wyniki sugerują, że Go jest optymalnym wyborem dla obliczeniowo intensywnych zadań, takich jak liczenie liczby pi z wysoką precyzją.
Wpływ precyzji na wyniki
Go i Python dość dobrze poradziły sobie z większą liczbą miejsc po przecinku, ich wydajność nie spadała zbyt drastycznie wraz ze zwiększającą się precyzją, natomiast Node.js odnotowywał praktycznie 2-krotny wzrost czasu potrzebnego na obliczenie dodatkowych 500 liczb po przecinku, jest to zaskakujące, ponieważ żaden język nie używał zaawansowanych optymalizacji, czy np. Goroutines. Co jeszcze ciekawsze na etapie pisania kodów źródłowych testowałem kilka możliwych algorytmów do liczenia Pi, wszystkie działały podobnie źle na środowisku Node, a zadowalająco lub dobrze na Go, czy Python.
Ograniczenia badania
Otrzymane wyniki są obiecujące, jednak należy pamiętać o pewnych ograniczeniach tego badania. Przede wszystkim testy przeprowadzono w ściśle określonych warunkach, co może nie odzwierciedlać rzeczywistych zastosowań. Warto rozważyć przeprowadzenie dodatkowych eksperymentów, np. z wykorzystaniem innych algorytmów obliczania liczby π, większych zbiorów danych lub różnych architektur sprzętowych. Ponadto warto zbadać wpływ optymalizacji kodu i wyboru bibliotek na wydajność poszczególnych języków. W przyszłości interesujące byłoby również porównać wydajność Go, Pythona i Node.js w innych typach obliczeń, takich jak przetwarzanie danych czy uczenie maszynowe.
Wnioski płynące z tego badania mają istotne implikacje dla praktycznego zastosowania tych języków. Deweloperzy tworzący aplikacje wymagające dużej wydajności obliczeniowej, takie jak systemy symulacyjne czy aplikacje naukowe, powinni poważnie rozważyć wybór języka Go. Z kolei, Python i Node.js mogą być bardziej odpowiednie dla projektów, w których wydajność nie jest głównym kryterium, a priorytetem jest szybkość rozwoju, czy łatwość integracji z innymi narzędziami.
Podsumowując, przeprowadzone testy potwierdzają wysoką wydajność języka Go w obliczeniach numerycznych. Jednakże, aby uzyskać pełniejszy obraz możliwości tych języków, konieczne są dalsze badania, które uwzględnią różne scenariusze zastosowań i ograniczenia poszczególnych technologii.
Podsumowanie
Reasumując badanie wykazało, że spośród 3 sprawdzanych języków niekwestionowanym zwycięzca pod względem wydajności jest Go, natomiast najgorzej wypadł JavaScript w Node.Js, Python uplasował się w środku stawki, lecz jego pozycja wcale nie odbiega aż tak znacząco od wydajności oferowanej przez Go szczególnie w przypadkach obliczania niskiej precyzji liczby Pi.
Rekomendacje
Moim zdaniem każdy język ma swoje zastosowanie, dla mniejszych, prostszych i niewymagających skomplikowanych obliczeń najlepszy będzie Node.Js, dla bardziej wymagających obliczeniowo, wymagających dużej skalowalności, obliczeń rozproszonych najlepszym wyborem będzie Go, natomiast tam, gdzie potrzebne jest uczenie maszynowe, wchodzą algorytmy Sztucznej inteligencji (AI), optymalnym wyborem będzie Python, ze swoją ogromną bazą narzędzi właśnie do tego celu. Ale i tak Liderem wydajności pozostanie Go.
Polecane artykuły
Docker vs Kubernetes: Który dla Ciebie w 2025?
Docker i Kubernetes objaśnione! Która technologia lepsza dla początkujących w 2025? Porównanie, przykłady i przyszłość.
Mateusz Kędziora
DevOps: Automatyzacja zadań sysadmina dla programistów
Zautomatyzuj pracę sysadmina w środowisku DevOps! Praktyczne przykłady, skrypty, Ansible, Terraform, Prometheus i Grafana.
Mateusz Kędziora
Automatyzacja Linux/macOS z Bash: Praktyczny Przewodnik
Zacznij automatyzować system Linux/macOS z Bash! Dowiedz się, czym jest Bash, jak pisać skrypty i używać podstawowych komend.
Mateusz Kędziora