Już na samym początku widać wyraźne różnice między Go i Rust. Go skupia się bardziej na budowaniu web API i małych usług, które mogą skalować się w nieskończoność, szczególnie dzięki mocy goroutines. To ostatnie jest również możliwe w Rust, ale rzeczy są znacznie trudniejsze z punktu widzenia doświadczenia dewelopera.
Rust działa dobrze do przetwarzania dużych ilości danych i innych operacji wymagających użycia procesora, takich jak wykonywanie algorytmów. To jest największa przewaga Rusta nad Go. Projekty wymagające wysokiej wydajności są generalnie lepiej przystosowane do Rusta.
W tym poradniku porównamy Go i Rust, oceniając każdy język programowania pod względem wydajności, współbieżności, zarządzania pamięcią i ogólnego doświadczenia programisty. Przedstawimy również przegląd tych elementów, aby pomóc Ci wybrać odpowiedni język dla Twojego projektu na pierwszy rzut oka.
Jeśli dopiero zaczynasz swoją przygodę z Rustem, dobrym pomysłem może być zapoznanie się z tym przewodnikiem dla początkujących, zanim zaczniesz czytać dalej.
Jeśli już wszystko załapałeś, zanurzmy się!
Wydajność
Pierwotnie zaprojektowany przez inżynierów Google, Go został przedstawiony publicznie w 2009 roku. Został stworzony, aby zaoferować alternatywę dla C++, która była łatwiejsza do nauczenia i kodowania oraz została zoptymalizowana do działania na wielordzeniowych procesorach.
Od tego czasu Go jest świetnym rozwiązaniem dla programistów, którzy chcą wykorzystać współbieżność, jaką oferuje ten język. Język dostarcza goroutines, które umożliwiają uruchamianie funkcji jako podprocesów.
Dużą zaletą Go jest to, jak łatwo można używać goroutines. Po prostu dodanie składni go
do funkcji powoduje, że jest ona uruchamiana jako podproces. Model współbieżności Go pozwala na rozmieszczenie obciążeń na wielu rdzeniach procesora, co czyni go bardzo wydajnym językiem.
package mainimport ( "fmt" "time")func f(from string) { for i := 0; i < 3; i++ { fmt.Println(from, ":", i) }}func main() { f("direct") go f("goroutine") time.Sleep(time.Second) fmt.Println("done")}
Mimo wsparcia dla wielordzeniowych procesorów, Rust wciąż przewyższa Go. Rust jest bardziej wydajny w wykonywaniu algorytmów i operacji wymagających dużej ilości zasobów. Gra Benchmarks porównuje Rust i Go dla różnych algorytmów, takich jak drzewa binarne. Dla wszystkich testowanych algorytmów Rust był szybszy o co najmniej 30 procent; w przypadku obliczeń na drzewach binarnych było to nawet 1000 procent. Badanie przeprowadzone przez Bitbucket pokazuje podobne wyniki, w których Rust jest na równi z C++.
(Źródło: Benchmarks Game)
Współbieżność
Jak wspomniano powyżej, Go obsługuje współbieżność. Na przykład, załóżmy, że uruchamiasz serwer WWW, który obsługuje żądania API. Możesz użyć goroutines Go, aby uruchomić każde żądanie jako podproces, maksymalizując wydajność przez odciążenie zadań do wszystkich dostępnych rdzeni procesora.
Goroutines są częścią wbudowanych funkcji Go, podczas gdy Rust otrzymał tylko natywną składnię async/await do obsługi współbieżności. W związku z tym przewaga doświadczenia programisty idzie do Go, jeśli chodzi o współbieżność. Jednak Rust jest znacznie lepszy w gwarantowaniu bezpieczeństwa pamięci.
Oto przykład uproszczonych wątków dla Rust:
use std::thread;use std::time::Duration;fn main() { // 1. create a new thread for i in 1..10 { thread::spawn(|| { println!("thread: number {}!", i); thread::sleep(Duration::from_millis(100)); }); } println!("hi from the main thread!");}
Współbieżność zawsze była drażliwym problemem dla programistów. Nie jest łatwym zadaniem zagwarantowanie współbieżności bezpiecznej dla pamięci bez uszczerbku dla doświadczenia programisty. Jednakże, to ekstremalne skupienie się na bezpieczeństwie doprowadziło do stworzenia współbieżności, którą można udowodnić. Rust eksperymentował z koncepcją własności, aby zapobiec niechcianemu dostępowi do zasobów w celu uniknięcia błędów związanych z bezpieczeństwem pamięci.
Rust oferuje cztery różne paradygmaty współbieżności, aby pomóc Ci uniknąć typowych pułapek związanych z bezpieczeństwem pamięci. Przyjrzymy się bliżej dwóm popularnym paradygmatom: kanałowi i blokadzie.
Kanał
Kanał pomaga w przekazywaniu wiadomości z jednego wątku do drugiego. Podczas gdy ta koncepcja istnieje również w Go, Rust pozwala na przekazywanie wskaźnika z jednego wątku do drugiego, aby uniknąć warunków wyścigu o zasoby. Poprzez przekazywanie wskaźników, Rust może wymusić izolację wątków dla kanałów. Ponownie, Rust pokazuje swoją obsesję na punkcie bezpieczeństwa pamięci w odniesieniu do swojego modelu współbieżności.
Lock
Dane są dostępne tylko wtedy, gdy blokada jest utrzymywana. Rust opiera się na zasadzie blokowania danych zamiast kodowania, co jest często spotykane w językach programowania takich jak Java.
Po więcej szczegółów na temat koncepcji własności i wszystkich paradygmatów współbieżności, sprawdź „Fearless Concurrency with Rust.”
Bezpieczeństwo pamięci
Wcześniejsza koncepcja własności jest jednym z głównych punktów sprzedaży Rusta. Rust przenosi bezpieczeństwo typu, które jest również ważne dla umożliwienia bezpiecznej dla pamięci współbieżności, na następny poziom.
Według bloga Bitbucket, „Bardzo surowy i pedantyczny kompilator Rusta sprawdza każdą zmienną, której używasz i każdy adres pamięci, do którego się odwołujesz. Unika możliwych warunków wyścigu danych i informuje cię o niezdefiniowanym zachowaniu.”
To oznacza, że nie skończysz z przepełnieniem bufora lub warunkiem wyścigu z powodu ekstremalnej obsesji Rusta na punkcie bezpieczeństwa pamięci. Jednakże, ma to również swoje wady. Na przykład, trzeba być nadświadomym zasad alokacji pamięci podczas pisania kodu. Nie jest łatwo mieć zawsze podniesioną gardę bezpieczeństwa pamięci.
Doświadczenie programisty
Po pierwsze, spójrzmy na krzywą uczenia się związaną z każdym językiem. Go został zaprojektowany z myślą o prostocie. Programiści często określają go jako „nudny” język, co oznacza, że jego ograniczony zestaw wbudowanych funkcji sprawia, że Go jest łatwy do zaadoptowania.
Co więcej, Go oferuje łatwiejszą alternatywę dla C++, ukrywając takie aspekty jak bezpieczeństwo pamięci i alokacja pamięci. Rust przyjmuje inne podejście, zmuszając cię do myślenia o koncepcjach takich jak bezpieczeństwo pamięci. Koncepcja własności i możliwość przekazywania wskaźników sprawia, że Rust jest mniej atrakcyjną opcją do nauki. Kiedy ciągle myślisz o bezpieczeństwie pamięci, jesteś mniej produktywny, a twój kod będzie bardziej skomplikowany.
Krzywa uczenia się dla Rusta jest dość stroma w porównaniu do Go. Warto jednak wspomnieć, że Go ma bardziej stromą krzywą uczenia się niż bardziej dynamiczne języki, takie jak Python i JavaScript.
Kiedy używać Go
Go działa dobrze w wielu różnych przypadkach użycia, co czyni go świetną alternatywą dla Node.js do tworzenia web API. Jak zauważył Loris Cro, „model współbieżności Go jest dobrym rozwiązaniem dla aplikacji po stronie serwera, które muszą obsługiwać wiele niezależnych żądań”. Właśnie dlatego Go dostarcza goroutines.
Co więcej, Go ma wbudowane wsparcie dla protokołu HTTP web. Możesz szybko zaprojektować mały interfejs API za pomocą wbudowanej obsługi HTTP i uruchomić go jako mikroserwis. Dlatego Go dobrze pasuje do architektury mikroserwisów i zaspokaja potrzeby programistów API.
W skrócie, Go jest dobrym rozwiązaniem, jeśli cenisz sobie szybkość rozwoju i przedkładasz prostotę składni nad wydajność. Na dodatek Go oferuje lepszą czytelność kodu, co jest ważnym kryterium dla dużych zespołów programistycznych.
Wybierz Go, gdy:
- Dbasz o prostotę i czytelność
- Chcesz mieć łatwą składnię do szybkiego pisania kodu
- Chcesz używać bardziej elastycznego języka, który wspiera rozwój sieci
Kiedy używać Rust
Rust jest świetnym wyborem, gdy liczy się wydajność, np. podczas przetwarzania dużych ilości danych. Co więcej, Rust daje Ci precyzyjną kontrolę nad tym, jak zachowują się wątki i jak zasoby są dzielone między wątkami.
Z drugiej strony, Rust wiąże się ze stromą krzywą uczenia się i spowalnia prędkość rozwoju z powodu dodatkowej złożoności bezpieczeństwa pamięci. Nie jest to koniecznie wadą; Rust gwarantuje również, że nie napotkasz błędów bezpieczeństwa pamięci, ponieważ kompilator sprawdza każdy wskaźnik danych. W przypadku złożonych systemów ta pewność może się przydać.
Wybierz Rust, gdy:
- Dbasz o wydajność
- Chcesz mieć drobnoziarnistą kontrolę nad wątkami
- Cenisz bezpieczeństwo pamięci nad prostotą
Go vs. Rust: My honest take
Zacznijmy od podkreślenia podobieństw. Zarówno Go jak i Rust są open-source’owe i zaprojektowane do wspierania architektury mikroserwisów i równoległych środowisk obliczeniowych. Oba optymalizują wykorzystanie dostępnych rdzeni procesora poprzez współbieżność.
Ale na koniec dnia, który język jest najlepszy?
Jest wiele sposobów na podejście do tego pytania. Polecam zastanowić się, jaki typ aplikacji chcesz zbudować. Go dobrze nadaje się do tworzenia aplikacji webowych i API, które wykorzystują wbudowane funkcje współbieżności, wspierając jednocześnie architekturę mikroserwisów.
Możesz również użyć Rusta do stworzenia web API, ale nie został on zaprojektowany z myślą o tym przypadku użycia. Koncentracja Rusta na bezpieczeństwie pamięci zwiększa złożoność i czas rozwoju, szczególnie w przypadku dość prostego API sieciowego. Jednak większa kontrola nad kodem pozwala na pisanie bardziej zoptymalizowanego, wydajnego pamięciowo i wydajnego kodu.
Mówiąc najprościej jak to możliwe, debata Go kontra Rust jest tak naprawdę kwestią prostoty kontra bezpieczeństwa.
Aby uzyskać więcej perspektyw, sprawdź „Wybór między Go a Rustem.”
LogRocket: Pełna widoczność w produkcyjnych aplikacjach Rust
Debugowanie aplikacji Rust może być trudne, szczególnie gdy użytkownicy doświadczają problemów, które są trudne do odtworzenia. Jeśli jesteś zainteresowany monitorowaniem i śledzeniem wydajności swoich aplikacji Rust, automatycznym wykrywaniem błędów oraz śledzeniem powolnych żądań sieciowych i czasu ładowania, wypróbuj LogRocket.
LogRocket jest jak rejestrator dla aplikacji internetowych, nagrywający dosłownie wszystko, co dzieje się w Twojej aplikacji Rust. Zamiast zgadywać, dlaczego zdarzają się problemy, możesz agregować i raportować, w jakim stanie była Twoja aplikacja, gdy wystąpił problem. LogRocket monitoruje również wydajność Twojej aplikacji, raportując takie wskaźniki jak obciążenie CPU klienta, wykorzystanie pamięci klienta i wiele więcej.
Unowocześnij sposób debugowania Twoich aplikacji Rust – zacznij monitorować za darmo.
.