Idź (język programowania) - Go (programming language)

Udać się
Idź Logo Blue.svg
Paradygmat Wieloparadygmat : współbieżny , funkcjonalny , imperatywny , obiektowy
Zaprojektowany przez Robert Griesemer
Rob Pike
Ken Thompson
Deweloper Autorzy Go
Po raz pierwszy pojawiły się 10 listopada 2009 ; 11 lat temu ( 2009-11-10 )
Wersja stabilna
1.17.1  Edytuj to na Wikidanych / 9 września 2021 r .; 40 dni temu ( 9 września 2021 )
Dyscyplina pisania Wnioskowane , statyczne , mocne , strukturalne , nominalne
Język implementacji Idź, język asemblera (gc); C++ (gofrontend)
OS DragonFly BSD , FreeBSD , Linux , macOS , NetBSD , OpenBSD , Plan 9 , Solaris , Windows
Licencja 3-klauzula BSD + udzielenie patentu
Rozszerzenia nazw plików .wybrać się
Strona internetowa golang .org
Główne wdrożenia
gc, gofrontend
Wpływem
C , Oberon-2 , Limbo , Active Oberon , komunikujące procesy sekwencyjne , Pascal , Oberon , Smalltalk , Newsqueak , Modula-2 , Alef , APL , BCPL , Modula , occam ,Erlang,
Pod wpływem
Odyn, Kryształ , Zig

Go to statycznie wpisane , skompilowany język programowania zaprojektowany w Google przez Roberta Griesemer , Rob Pike i Kena Thompsona . Go jest składniowo podobny do C , ale z bezpieczeństwem pamięci , wyrzucaniem elementów bezużytecznych , typowaniem strukturalnym i współbieżnością w stylu CSP . Język jest często określany jako Golang ze względu na nazwę domeny , ale właściwa nazwa to Go. golang.org

Istnieją dwie główne implementacje:

Trzecia partia- source do źródła kompilator , GopherJS, kompiluje Przejdź do JavaScriptu na tworzenie stron internetowych front-end .

Historia

Go został zaprojektowany w Google w 2007 roku w celu zwiększenia produktywności programowania w erze wielordzeniowych , sieciowych maszyn i dużych baz kodu . Projektanci chcieli odpowiedzieć na krytykę innych języków używanych w Google , ale zachowali ich przydatne cechy:

Projektanci byli przede wszystkim motywowani wspólną niechęcią do C++ .

Go został publicznie ogłoszony w listopadzie 2009 roku, a wersja 1.0 została wydana w marcu 2012 roku. Go jest powszechnie używany w produkcji w Google oraz w wielu innych organizacjach i projektach open-source.

Językiem programowania Mascot of Go jest Suseł pokazany powyżej.

W listopadzie 2016 r. czcionki Go i Go Mono zostały wydane przez projektantów czcionek Charlesa Bigelowa i Krisa Holmesa specjalnie do użytku w projekcie Go. Go to humanista bezszeryfowy, który przypomina Lucidę Grande, a Go Mono jest jednopozycyjny . Każda z czcionek jest zgodna z zestawem znaków WGL4 i została zaprojektowana tak, aby była czytelna z dużą wysokością x i wyraźnymi formami liter . Zarówno Go, jak i Go Mono są zgodne z normą DIN 1450, posiadając ukośne zero, małe litery lz ogonem i wielkie litery Iz szeryfami.

W kwietniu 2018 r. oryginalne logo zostało zastąpione stylizowanym, skośnym logo GO z spływami opływowymi. Jednak maskotka Gopher pozostała taka sama.

W sierpniu 2018 r. główni współtwórcy Go opublikowali dwa „projekty robocze” nowych i niezgodnych funkcji języka „Go 2”, typów ogólnych i obsługi błędów , a także poprosili użytkowników Go o przesłanie opinii na ich temat. Brak wsparcia dla programowania generycznego i gadatliwość obsługi błędów w Go 1.x wywołały znaczną krytykę .

Historia wersji

Go 1 gwarantuje zgodność specyfikacji języka i głównych części biblioteki standardowej. Wszystkie wersje do aktualnego wydania Go 1.17 zachowały tę obietnicę.

Każda główna wersja Go jest obsługiwana do momentu pojawienia się dwóch nowszych głównych wydań.

Historia wersji Go
Wersja główna Pierwsza data wydania Zmiany językowe Inne zmiany
1-1.0.3 2012-03-28 Pierwsze wydanie
1.1–1.1.2 2013-05-13
  • W Go 1.1 dzielenie liczb całkowitych przez stałą zero nie jest dozwolonym programem, więc jest to błąd w czasie kompilacji.
  • Definicja literałów łańcuchowych i runicznych została udoskonalona, ​​aby wykluczyć zastępcze połówki z zestawu prawidłowych punktów kodowych Unicode.
  • Poluzowane zasady dotyczące wymagań zwrotów. Jeśli kompilator może udowodnić, że funkcja zawsze zwraca przed osiągnięciem końca funkcji, można pominąć końcową instrukcję kończącą.
  • Język pozwala implementacji wybrać, czy inttyp i uinttypy są 32 lub 64 bitowe.
  • W architekturze 64-bitowej maksymalny rozmiar sterty został znacznie powiększony, z kilku gigabajtów do kilkudziesięciu gigabajtów.
  • Dodanie detektora wyścigu do standardowego zestawu narzędzi.
1.2–1.2.2 2013-12-01
  • Język określa teraz, że ze względów bezpieczeństwa niektóre zastosowania wskaźników zerowych gwarantują wywołanie paniki w czasie wykonywania.
  • Go 1.2 dodaje możliwość określenia pojemności, a także długości podczas korzystania z operacji krojenia na istniejącej tablicy lub wycinku. Operacja wycinania tworzy nowy wycinek, opisując ciągłą sekcję już utworzonej tablicy lub wycinka.
  • Harmonogram środowiska wykonawczego można teraz wywoływać w przypadku (niewbudowanych) wywołań funkcji.
  • Go 1.2 wprowadza konfigurowalny limit (domyślnie 10 000) całkowitej liczby wątków, które może mieć jeden program.
  • W Go 1.2 minimalny rozmiar stosu podczas tworzenia gorutyny został podniesiony z 4 KB do 8 KB.
1.3-1.3.3 2014-06-18 W tej wersji nie ma zmian językowych.
  • Model pamięci Go 1.3 dodaje nową regułę dotyczącą wysyłania i odbierania w buforowanych kanałach, aby wyraźnie zaznaczyć, że buforowany kanał może być używany jako prosty semafor, używając wysyłania do kanału do akwizycji i odbierania z kanału do zwolnienia.
  • Go 1.3 zmienił implementację stosów gorutynowych ze starego, "segmentowanego" modelu na model ciągły.
  • Od jakiegoś czasu garbage collector był precyzyjny podczas sprawdzania wartości w stercie; wersja Go 1.3 dodaje równoważną precyzję do wartości na stosie.
  • Iteracje na małych mapach nie odbywają się już w spójnej kolejności. Wynika to z nadużywania przez programistów zachowań związanych z implementacją.
1.4-1.4.3 2014-12-10
  • Wyrażenie zakresu bez przypisania
  • Automatyczne podwójne dereferencje w wywołaniach metod są teraz niedozwolone w gc i gccgo. Jest to zmiana niekompatybilna wstecz, ale zgodna ze specyfikacją języka.
  • W wersji 1.4 znaczna część kodu środowiska uruchomieniowego została przetłumaczona na Go, aby garbage collector mógł skanować stosy programów w środowisku wykonawczym i uzyskać dokładne informacje o tym, które zmienne są aktywne.
  • Język akceptowany przez monterów cmd/5a, cmd/6ai cmd/8amiał kilka zmian, głównie, aby ułatwić dostarczanie informacji o typie w czasie wykonywania.
  • Dodanie pakietów wewnętrznych.
  • Nowa podkomenda przejdź do generowania.
1,5–1,5.4 2015-08-19

Z powodu przeoczenia reguła, która pozwalała na usunięcie typu elementu z literałów wycinków, nie została zastosowana do kluczy mapowania. Zostało to poprawione w Go 1.5.

  • Kompilator i środowisko uruchomieniowe są teraz zaimplementowane w Go i asemblerze, bez C. Teraz, gdy kompilator i środowisko uruchomieniowe Go są zaimplementowane w Go, kompilator Go musi być dostępny, aby skompilować dystrybucję ze źródła. Kompilator jest teraz samoobsługowy.
  • Odśmiecacz został przeprojektowany w wersji 1.5. Faza "zatrzymania świata" kolektora będzie prawie zawsze trwała poniżej 10 milisekund, a zwykle znacznie mniej.
  • W Go 1.5 zmieniono kolejność planowania gorutyn.
1,6-1,6,4 2016-02-17 W tej wersji nie ma zmian językowych.
  • Poważna zmiana została dokonana w cgo definiującym zasady współdzielenia wskaźników Go z kodem C, aby zapewnić, że taki kod C może współistnieć z garbage collectorem Go.
  • Parser Go jest teraz pisany ręcznie, a nie generowany.
  • go vetPolecenie diagnozuje się przechodząc wartości funkcji lub sposób, jak argumenty Printf, na przykład przy przejściu f, gdy f()zamierzone.
1,7–1,7.6 2016-08-15

Wyjaśnienie dotyczące instrukcji kończących w specyfikacji języka. Nie zmienia to dotychczasowego zachowania.

  • W przypadku 64-bitowych systemów x86 dodano następujące instrukcje (patrz SSE ): PCMPESTRI, RORXL, RORXQ, VINSERTI128, VPADDD, VPADDQ, VPALIGNR, VPBLENDD, VPERM2F128, VPERM2I128, VPOR, VPSHUFB, VPSHUFD, VPSLLD, VPSLLDQ, VPSLLQ, VPSRLD, VPSRLDQ, i VPSRLQ.
  • Ta wersja zawiera nowe zaplecze generowania kodu dla 64-bitowych systemów x86, oparte na SSA .
  • Pakiety używające cgo mogą teraz zawierać pliki źródłowe Fortran (oprócz C, C++, Objective C i SWIG), chociaż powiązania Go muszą nadal używać interfejsów API języka C.
  • Nowa podkomenda " go tool dist list" drukuje wszystkie obsługiwane pary system operacyjny/architektura.
1,8–1,8.7 2016-02-16

Podczas jawnej konwersji wartości z jednego typu struktury na inny, od wersji Go 1.8 znaczniki są ignorowane. W ten sposób dwie struktury, które różnią się tylko znacznikami, mogą zostać przekonwertowane z jednej na drugą.

  • W przypadku 64-bitowych systemów x86 dodano następujące instrukcje: VBROADCASTSD, BROADCASTSS, MOVDDUP, MOVSHDUP, MOVSLDUP, VMOVDDUP, VMOVSHDUP, i VMOVSLDUP.
  • Przerwy w zbieraniu śmieci powinny być znacznie krótsze niż w Go 1.7, zwykle poniżej 100 mikrosekund, a często nawet 10 mikrosekund. Aby uzyskać szczegółowe informacje, zapoznaj się z dokumentem na temat eliminowania ponownego skanowania stosu typu „stop-the-world”.
  • Narzut odroczonych wywołań funkcji został zmniejszony o około połowę.
  • Narzut połączeń z Go do C został zmniejszony o około połowę.
1,9-1,9.7 2017-08-24
  • Go obsługuje teraz aliasy typów.
  • Wymuś zaokrąglanie pośrednie w arytmetyce zmiennoprzecinkowej.

Kompilator Go obsługuje teraz równoległe kompilowanie funkcji pakietu, korzystając z wielu rdzeni.

1,10–1,10,7 2018-02-16
  • Wyjaśniono przypadek narożny dotyczący przesunięć niewpisanych stałych.
  • Gramatyka wyrażeń metod została zaktualizowana w celu złagodzenia składni i umożliwienia dowolnego wyrażenia typu jako odbiornika.

Dla 64-bitowego portu x86 asembler obsługuje teraz 359 nowych instrukcji, w tym pełne zestawy rozszerzeń AVX, AVX2, BMI, BMI2, F16C, FMA3, SSE2, SSE3, SSSE3, SSE4.1 i SSE4.2. Asembler również nie implementuje już MOVL $0, AXjako XORLinstrukcji, aby uniknąć nieoczekiwanego usuwania flag stanu.

1,11–1,11,6 2018-08-24 W tej wersji nie ma zmian językowych.
  • Go 1.11 dodaje eksperymentalny port do WebAssembly .
  • Go 1.11 dodaje wstępne wsparcie dla nowej koncepcji zwanej "modułami", alternatywy dla GOPATH ze zintegrowaną obsługą wersjonowania i dystrybucji pakietów.
  • Na razie asembler amd64akceptuje instrukcje AVX512.
  • Go 1.11 porzuca wsparcie dla Windows XP i Windows Vista.
  • Przejdź do wersji 1.11.3 i nowszej, napraw usterkę uwierzytelniania TLS w pakiecie crypto/x509.
1.12.1 2019-02-25 W tej wersji nie ma zmian językowych.
  • Opt-in wsparcie dla TLS 1.3
  • Ulepszona obsługa modułów (w przygotowaniu do bycia domyślnym w Go 1.13)
  • Wsparcie dla windows/arm
  • Poprawiona kompatybilność z macOS i iOS
1.13.1 2019-09-03

Go obsługuje teraz bardziej jednolity i zmodernizowany zestaw przedrostków literowych liczb

  • wsparcie dla TLS 1.3 w pakiecie crypto/tls domyślnie (opt-out zostanie usunięty w Go 1.14)
  • Wsparcie dla owijania błędów
1.14 2020-02-25

Umożliwia osadzanie interfejsów z nakładającymi się zestawami metod

Obsługa modułów w gopoleceniu jest teraz gotowa do użytku produkcyjnego

1.15 2020-08-11 W tej wersji nie ma zmian językowych.
  • Nowy wbudowany pakiet czasu/tzdata
  • Czasowniki drukowania %#gi %#Gteraz zachowują końcowe zera dla wartości zmiennoprzecinkowych
  • Pakiet reflectteraz uniemożliwia dostęp do metod wszystkich niewyeksportowanych pól, podczas gdy wcześniej umożliwiał dostęp do nieeksportowanych, osadzonych pól.
1,16 2021-02-16 W tej wersji nie ma zmian językowych.
  • Nowa obsługa osadzania plików w programie go
  • Wsparcie dla macos/ramię
  • Tryb uwzględniania modułów jest domyślnie włączony
1,17 2021-08-16 W tej wersji nie ma zmian językowych.
  • Ta aktualizacja modyfikuje głównie wewnętrzne elementy Go

Projekt

Go jest pod wpływem C (zwłaszcza dialektu Plan 9), ale z naciskiem na większą prostotę i bezpieczeństwo. Język składa się z:

Składnia

Składnia Go zawiera zmiany z C mające na celu zachowanie zwięzłości i czytelności kodu. Wprowadzono połączony operator deklaracji/inicjowania, który umożliwia programiście pisanie i := 3lub s := "Hello, world!", bez określania typów używanych zmiennych. To kontrastuje z C int i = 3;i const char *s = "Hello, world!";. Średniki nadal kończą instrukcje, ale są niejawne, gdy występuje koniec wiersza. Metody mogą zwracać wiele wartości, a zwrócenie result, errpary jest konwencjonalnym sposobem, w jaki metoda wskazuje błąd wywołującemu go w Go. Go dodaje dosłowne składnie do inicjowania parametrów struktury według nazwy oraz do inicjowania map i wycinków . Jako alternatywę dla trzyinstancyjnej forpętli C, rangewyrażenia Go pozwalają na zwięzłe iteracje po tablicach, wycinkach, ciągach, mapach i kanałach.

Rodzaje

Go ma wiele wbudowanych typów, w tym numeryczne ( byte , int64 , float32 , itd.), wartości logiczne i ciągi znaków ( string ). Ciągi są niezmienne; wbudowane operatory i słowa kluczowe (zamiast funkcji) zapewniają łączenie, porównywanie i kodowanie/dekodowanie UTF-8 . Typy rekordów można zdefiniować za pomocą słowa kluczowego struct .

Dla każdego typu T i każdej nieujemnej stałej liczby całkowitej n istnieje typ tablicy oznaczony [ n ] T ; tablice o różnej długości są zatem różnego typu. Tablice dynamiczne są dostępne jako „plasterki”, oznaczone [] T dla niektórych typów T . Mają one długość i pojemność określającą, kiedy należy przydzielić nową pamięć w celu rozszerzenia tablicy. Kilka wycinków może współdzielić swoją podstawową pamięć.

Wskaźniki są dostępne dla wszystkich typów, a typ wskaźnika do T jest oznaczony * T . Przejmowanie adresów i pośrednictwo wykorzystują operatory & i * , jak w C, lub występują niejawnie przez wywołanie metody lub składnię dostępu do atrybutów. Nie ma arytmetyki wskaźnika, z wyjątkiem specjalnego typu unsafe.Pointer w bibliotece standardowej.

Dla pary typów K , V , typ map[ K ] V jest typem tablic mieszających mapujących klucze typu K na wartości typu V. Tabele haszujące są wbudowane w język, ze specjalną składnią i wbudowanymi funkcjami. chan T to kanał, który umożliwia przesyłanie wartości typu T pomiędzy współbieżnymi procesami Go .

Oprócz obsługi interfejsów , system typów Go jest nominalny : słowo kluczowe type może być użyte do zdefiniowania nowego nazwanego typu , który różni się od innych nazwanych typów, które mają ten sam układ (w przypadku struct , ci sami członkowie w to samo zamówienie). Niektóre konwersje między typami (np. między różnymi typami całkowitymi) są wstępnie zdefiniowane, a dodanie nowego typu może zdefiniować dodatkowe konwersje, ale konwersje między nazwanymi typami muszą być zawsze wywoływane jawnie. Na przykład słowo kluczowe type może służyć do definiowania typu adresów IPv4 , na podstawie 32-bitowych liczb całkowitych bez znaku:

type ipv4addr uint32

W przypadku tej definicji typu ipv4addr(x) interpretuje wartość x uint32 jako adres IP. Proste przypisanie x do zmiennej typu ipv4addr jest błędem typu.

Wyrażenia stałe mogą być wpisane lub niewpisane; otrzymują typ po przypisaniu do zmiennej typu, jeśli wartość, którą reprezentują, przechodzi kontrolę w czasie kompilacji.

Typy funkcji są oznaczone słowem kluczowym func ; przyjmują zero lub więcej parametrów i zwracają zero lub więcej wartości, z których wszystkie są wpisane. Wartości parametru i zwracane określają typ funkcji; zatem func(string, int32) (int, error) jest typem funkcji, które pobierają string i 32-bitową liczbę całkowitą ze znakiem i zwracają liczbę całkowitą ze znakiem (o domyślnej szerokości) oraz wartość typu wbudowanego interfejsu błąd .

Każdy nazwany typ ma skojarzony z nim zestaw metod . Powyższy przykład adresu IP można rozszerzyć o metodę sprawdzania, czy jego wartość jest znanym standardem:

// ZeroBroadcast reports whether addr is 255.255.255.255.
func (addr ipv4addr) ZeroBroadcast() bool {
    return addr == 0xFFFFFFFF
}

Ze względu na typowanie nominalne ta definicja metody dodaje metodę do ipv4addr , ale nie do uint32 . Chociaż metody mają specjalną definicję i składnię wywołania, nie ma odrębnego typu metody.

System interfejsu

Go udostępnia dwie funkcje, które zastępują dziedziczenie klas .

Pierwszym z nich jest osadzanie , które może być postrzegane jako zautomatyzowana forma kompozycji lub delegowania .

Drugi to interfejsy , które zapewniają polimorfizm środowiska uruchomieniowego . Interfejsy są klasą typów i zapewniają ograniczoną formę typowania strukturalnego w skądinąd nominalnym systemie typów Go. Obiekt, który jest typem interfejsu, jest również innego typu, podobnie jak obiekty C++ będące jednocześnie klasą bazową i pochodną. Interfejsy Go zostały zaprojektowane na podstawie protokołów z języka programowania Smalltalk. Wiele źródeł używa terminu pisanie kaczką podczas opisywania interfejsów Go. Chociaż termin kaczki typowania nie jest precyzyjnie zdefiniowany i dlatego nie jest błędny, zwykle oznacza, że ​​zgodność typu nie jest sprawdzana statycznie. Ponieważ zgodność z interfejsem Go jest sprawdzana statycznie przez kompilator Go (z wyjątkiem wykonywania asercji typu), autorzy Go preferują termin typowanie strukturalne .

Definicja typu interfejsu zawiera listę wymaganych metod według nazwy i typu. Każdy obiekt typu T, dla którego istnieją funkcje pasujące do wszystkich wymaganych metod interfejsu typu I, jest również obiektem typu I. Definicja typu T nie musi (i nie może) identyfikować typu I. Na przykład, jeśli Kształt , Kwadrat i Okrąg są zdefiniowane jako

import "math"

type Shape interface {
    Area() float64
}

type Square struct { // Note: no "implements" declaration
    side float64
}

func (sq Square) Area() float64 { return sq.side * sq.side }

type Circle struct { // No "implements" declaration here either
    radius float64
}

func (c Circle) Area() float64 { return math.Pi * math.Pow(c.radius, 2) }

wtedy zarówno Kwadrat i koło są niejawnie Kształt i może być przypisany do Shape zmiennej -typed. W języku formalnym system interfejsów Go zapewnia typowanie strukturalne, a nie nominalne . Interfejsy mogą osadzać inne interfejsy, tworząc połączony interfejs, który jest obsługiwany przez dokładnie typy implementujące interfejs osadzony i wszelkie metody dodane przez nowo zdefiniowany interfejs.

Standardowa biblioteka Go używa interfejsów, aby zapewnić uniwersalność w kilku miejscach, w tym system wejścia/wyjścia oparty na koncepcjach Reader i Writer .

Oprócz wywoływania metod za pośrednictwem interfejsów, Go umożliwia konwersję wartości interfejsów na inne typy za pomocą sprawdzania typu w czasie wykonywania. Konstrukcje języka, które to umożliwiają, to asercja typu , która sprawdza jeden potencjalny typ, oraz przełącznik typu , który sprawdza wiele typów.

Pusty interfejs interface{} jest ważnym wariant podstawowy, ponieważ może odnosić się do elementu dowolnego rodzaju betonu. Jest podobna do klasy Object w Javie lub C# i jest spełniana przez dowolny typ, w tym typy wbudowane, takie jak int . Kod używający pustego interfejsu nie może po prostu wywoływać metod (lub wbudowanych operatorów) na obiekcie, do którego się odwołuje, ale może przechowywać interface{}wartość, próbować przekonwertować ją na bardziej użyteczny typ za pomocą asercji typu lub przełącznika typu lub sprawdzić go z reflectpakietem Go . Ponieważ interface{}może odnosić się do dowolnej wartości, jest to ograniczony sposób na uniknięcie ograniczeń statycznego typowania, jak void*w C, ale z dodatkowymi kontrolami typu w czasie wykonywania.

interface{}Typu mogą być stosowane do modelowania ustrukturyzowanych danych w dowolnym schemacie Go, takich jak JSON lub YAML danych, przedstawiając go jako map[string]interface{}(mapa sznurkiem do pustej Interface). To rekurencyjnie opisuje dane w postaci słownika z kluczami ciągów i wartościami dowolnego typu.

Wartości interfejsu są implementowane przy użyciu wskaźnika do danych i drugiego wskaźnika do informacji o typie w czasie wykonywania. Podobnie jak niektóre inne typy zaimplementowane za pomocą wskaźników w Go, wartości interfejsu są nilniezainicjowane.

System pakietów

W systemie pakietów Go każdy pakiet ma ścieżkę (np. "compress/bzip2"lub "golang.org/x/net/html") i nazwę (np. bzip2lub html). Odniesienia do definicji innych pakietów muszą być zawsze poprzedzone nazwą innego pakietu, a dostępne są tylko nazwy pisane wielkimi literami z innych pakietów: io.Readersą publiczne, ale bzip2.readernie są. go getPolecenie może pobrać pakiety zapisane w zdalnym repozytorium i deweloperzy są zachęcani do rozwijania pakietów wewnątrz ścieżki bazowej odpowiadających repozytorium źródłowym (takie jak example.com/user_name/package_name), aby zmniejszyć prawdopodobieństwo kolizji z nazwy przyszłych dodatków do standardu biblioteka lub inne biblioteki zewnętrzne.

Istnieją propozycje wprowadzenia odpowiedniego rozwiązania do zarządzania pakietami dla idź podobny do CPAN dla Perl lub Rust „s układu ładunków lub Node ” systemu npm s.

Współbieżność: gorutyny i kanały

Język Go ma wbudowane funkcje, a także obsługę bibliotek do pisania programów współbieżnych . Współbieżność odnosi się nie tylko do równoległości procesora, ale także do asynchronii : pozwala na uruchamianie powolnych operacji, takich jak baza danych lub odczyt sieci, podczas gdy program wykonuje inną pracę, co jest powszechne w przypadku serwerów opartych na zdarzeniach.

Podstawową konstrukcją współbieżności jest gorutyna , rodzaj lekkiego procesu . Wywołanie funkcji poprzedzone gosłowem kluczowym uruchamia funkcję w nowej gorutynie. Specyfikacja języka nie określa, w jaki sposób powinny być zaimplementowane gorutyny, ale obecne implementacje multipleksują gorutyny procesu Go na mniejszy zestaw wątków systemu operacyjnego , podobnie do planowania wykonywanego w Erlang .

Podczas gdy dostępny jest standardowy pakiet biblioteki zawierający większość klasycznych struktur kontroli współbieżności ( blokady mutex itp.), idiomatyczne programy współbieżne preferują zamiast tego kanały , które zapewniają wysyłanie wiadomości między gorutynami. Opcjonalne bufory przechowują wiadomości w kolejności FIFO i umożliwiają wysyłanie gorutyn przed odebraniem ich wiadomości.

Kanały są typowane tak, że kanał typu chan T może być używany tylko do przesyłania wiadomości typu T . Do działania na nich używana jest specjalna składnia; <-ch to wyrażenie, które powoduje, że wykonująca się gorutyna blokuje się, dopóki wartość nie nadejdzie przez kanał ch , podczas gdy ch < -x wysyła wartość x (prawdopodobnie blokuje do momentu, gdy inna gorutyna otrzyma tę wartość). Wbudowana instrukcja select, podobna do przełącznika , może być używana do implementacji nieblokującej komunikacji na wielu kanałach; patrz poniżej na przykład. Go ma model pamięci opisujący, w jaki sposób gorutyny muszą używać kanałów lub innych operacji, aby bezpiecznie udostępniać dane.

Istnienie kanałów odróżnia Go od języków współbieżnych w stylu aktora, takich jak Erlang, gdzie komunikaty są adresowane bezpośrednio do aktorów (odpowiadając gorutynom). Styl aktora można symulować w Go, utrzymując korespondencję jeden do jednego między gorutynami i kanałami, ale język pozwala wielu gorutynom współdzielić kanał lub jednej gorutynowi do wysyłania i odbierania na wielu kanałach.

Z tych narzędzi można budować współbieżne konstrukcje, takie jak pule robocze, potoki (w których, powiedzmy, plik jest dekompresowany i analizowany podczas pobierania), wywołania w tle z limitem czasu, równoległe wywołania zestawu usług i inne . Kanały znalazły również zastosowania odbiegające od zwykłego pojęcia komunikacji międzyprocesowej, takie jak służenie jako bezpieczna dla współbieżności lista buforów poddanych recyklingowi, implementowanie współprogramów (co pomogło zainspirować nazwę gorutyna ) i implementowanie iteratorów .

Konwencje strukturalne Go związane ze współbieżnością ( kanały i wejścia kanałów alternatywnych) wywodzą się z modelu sekwencyjnego komunikowania się Tony'ego Hoare'a . W przeciwieństwie do poprzednich współbieżnych języków programowania, takich jak Occam lub Limbo (język, nad którym pracował współtwórca Go, Rob Pike), Go nie zapewnia żadnego wbudowanego pojęcia bezpiecznej lub weryfikowalnej współbieżności. Chociaż model procesów komunikacyjnych jest faworyzowany w Go, nie jest jedynym: wszystkie gorutyny w programie współdzielą jedną przestrzeń adresową. Oznacza to, że mutowalne obiekty i wskaźniki mogą być współużytkowane przez gorutyny; patrz § Brak bezpieczeństwa warunków wyścigu , poniżej.

Przydatność do programowania równoległego

Chociaż funkcje współbieżności Go nie są przeznaczone głównie do przetwarzania równoległego , mogą być używane do programowania maszyn wieloprocesorowych ze współdzieloną pamięcią . Przeprowadzono różne badania nad skutecznością tego podejścia. W jednym z tych badań porównano rozmiar (w liniach kodu ) i szybkość programów napisanych przez doświadczonego programistę nie znającego języka i poprawki do tych programów wykonane przez eksperta Go (z zespołu programistów Google), robiąc to samo dla Chapel , Cilk i Intel TBB . Badanie wykazało, że niespecjaliści mieli tendencję do pisania algorytmów dziel i zwyciężaj za pomocą jednej instrukcji go na rekurencję, podczas gdy ekspert pisał programy dystrybuujące-synchronizujące pracę przy użyciu jednej gorutyny na procesor. Programy eksperta były zwykle szybsze, ale też dłuższe.

Brak bezpieczeństwa w warunkach wyścigu

Nie ma ograniczeń co do tego, w jaki sposób gorutyny uzyskują dostęp do współdzielonych danych, dzięki czemu możliwe są warunki wyścigu . W szczególności, chyba że program jawnie synchronizuje się za pośrednictwem kanałów lub innych środków, zapisy z jednej gorutyny mogą być częściowo, całkowicie lub w ogóle niewidoczne dla innej, często bez gwarancji kolejności zapisów. Co więcej, wewnętrzne struktury danych Go, takie jak wartości interfejsów, nagłówki wycinków, tablice mieszające i nagłówki ciągów, nie są odporne na warunki wyścigu, więc bezpieczeństwo typów i pamięci może zostać naruszone w programach wielowątkowych, które modyfikują współdzielone wystąpienia tych typów bez synchronizacji. Zamiast obsługi języków bezpieczne programowanie współbieżne opiera się zatem na konwencjach; na przykład Chisnall zaleca idiom o nazwie „aliasy xor mutable”, co oznacza, że ​​przekazanie zmiennej wartości (lub wskaźnika) nad kanałem sygnalizuje przeniesienie własności nad wartością do odbiorcy.

Binaria

Linker w łańcuchu narzędzi gc domyślnie tworzy statycznie połączone pliki binarne; dlatego wszystkie pliki binarne Go zawierają środowisko uruchomieniowe Go.

Pominięcia

Go celowo pomija pewne funkcje wspólne w innych językach, w tym dziedziczenie (implementacji) , programowanie generyczne , asercje , arytmetykę wskaźników , niejawne konwersje typów , unie nieoznaczone i unie tagowane . Projektanci dodali tylko te udogodnienia, na które zgodzili się wszyscy trzej.

Spośród pominiętych funkcji językowych projektanci wyraźnie sprzeciwiają się twierdzeniom i arytmetyce wskaźników, jednocześnie broniąc wyboru pominięcia dziedziczenia typów jako dającego bardziej użyteczny język, zachęcając zamiast tego do korzystania z interfejsów w celu uzyskania dynamicznej wysyłki i kompozycji w celu ponownego użycia kodu. Skład i delegowanie są w rzeczywistości w dużej mierze zautomatyzowane przez osadzanie struktur ; według badaczy Schmager et al. , ta funkcja „ma wiele wad dziedziczenia: wpływa na publiczny interfejs obiektów, nie jest szczegółowa (tj. nie ma kontroli na poziomie metody nad osadzaniem), metody osadzonych obiektów nie mogą być ukryte i jest statyczna ”, czyniąc „nieoczywistym”, czy programiści będą nadużywać go do tego stopnia, że ​​programiści w innych językach są znani z nadużywania dziedziczenia.

Projektanci wyrażają otwartość na programowanie generyczne i zauważają, że funkcje wbudowane w rzeczywistości rodzajowe, ale są one traktowane jako przypadki specjalne; Pike nazywa to słabością, która w pewnym momencie może ulec zmianie. Zespół Google zbudował co najmniej jeden kompilator dla eksperymentalnego dialektu Go z generykami, ale go nie wydał. Są również otwarci na standaryzację sposobów stosowania generowania kodu. W czerwcu 2020 opublikowano nowy projekt dokumentu projektowego, który dodałby do Go niezbędną składnię do deklarowania ogólnych funkcji i typów. Dostarczono narzędzie do tłumaczenia kodu go2go, aby umożliwić użytkownikom wypróbowanie nowej składni, wraz z wersją internetowego Go Playground z obsługą generyków.

Początkowo pominięty, wyjątek -Jak paniki / odzyskać mechanizm ostatecznie został dodany, których autorzy zalecają Go użyciem Nieodwracalne błędy, takie jak te, które powinny zatrzymać całą prośbę programu lub serwera, albo jako skrót do propagacji błędów w górę stosu w opakowaniu (ale nie poza granicami pakietu; tam zwracane są błędy są standardowym API).

Styl

Autorzy Go włożyli wiele wysiłku w wpływanie na styl programów Go:

  • Wcięcia, odstępy i inne szczegóły kodu na poziomie powierzchni są automatycznie standaryzowane przez gofmtnarzędzie. golintwykonuje dodatkowe kontrole stylu automatycznie.
  • Narzędzia i biblioteki rozpowszechniane wraz z Go sugerują standardowe podejście do takich rzeczy jak dokumentacja API ( godoc), testowanie ( go test), budowanie ( go build), zarządzanie pakietami ( go get) i tak dalej.
  • Go wymusza reguły, które są zaleceniami w innych językach, na przykład zabraniają zależności cyklicznych, nieużywanych zmiennych lub importów oraz niejawnych konwersji typów.
  • Pominięcie niektórych funkcji (na przykład skróty funkcjonalno-programowe, jak mapi Java-style try/ finallybloki) zmierza do zachęcania do konkretnego wyraźny, konkretnych i imperatyw styl programowania.
  • Pierwszego dnia zespół Go opublikował kolekcję idiomów Go, a później zebrał także komentarze dotyczące przeglądu kodu, przemówienia i oficjalne wpisy na blogu, aby uczyć stylu Go i filozofii kodowania.

Narzędzia

Główna dystrybucja Go zawiera narzędzia do budowania , testowania i analizowania kodu:

  • go build, który buduje binaria Go używając tylko informacji z samych plików źródłowych, bez oddzielnych plików makefile
  • go test, do testów jednostkowych i mikrobenchmarków
  • go fmt, do formatowania kodu
  • go install, do pobierania i instalowania zdalnych pakietów
  • go vet, statyczny analizator szukający potencjalnych błędów w kodzie
  • go run, skrót do budowania i wykonywania kodu
  • godoc, do wyświetlania dokumentacji lub jej obsługi przez HTTP
  • gorename, do zmiany nazw zmiennych, funkcji itd. w sposób bezpieczny dla typu
  • go generate, standardowy sposób wywoływania generatorów kodu

Obejmuje również obsługę profilowania i debugowania , oprzyrządowanie środowiska uruchomieniowego (na przykład do śledzenia przerw w wyrzucaniu elementów bezużytecznych ) oraz tester warunków wyścigu .

Ekosystem narzędzi innych firm wzbogaca standardową dystrybucję, takich jak gocode, który umożliwia automatyczne uzupełnianie kodu w wielu edytorach tekstu, goimports, który automatycznie dodaje/usuwa importy pakietów w razie potrzeby, oraz errcheck, który wykrywa kod, który może przypadkowo zignorować błędy.

Przykłady

Witaj świecie

package main

import "fmt"

func main() {
    fmt.Println("Hello, world!")
}

gdzie „FMT” to pakiet dla sformatowana I / O , podobny do C w wejściowym pliku C / wyjścia .

Konkurencja

Poniższy prosty program demonstruje funkcje współbieżności Go w celu zaimplementowania programu asynchronicznego. Uruchamia dwa lekkie wątki ("gorutyny"): jeden czeka, aż użytkownik wpisze jakiś tekst, podczas gdy drugi implementuje limit czasu. Instrukcja select czeka, aż któryś z tych gorutyn wyśle ​​wiadomość do głównej procedury i działa na pierwszej wiadomości, która nadejdzie (przykład zaadaptowany z książki Davida Chisnalla).

package main

import (
    "fmt"
    "time"
)

func readword(ch chan string) {
    fmt.Println("Type a word, then hit Enter.")
    var word string
    fmt.Scanf("%s", &word)
    ch <- word
}

func timeout(t chan bool) {
    time.Sleep(5 * time.Second)
    t <- false
}

func main() {
    t := make(chan bool)
    go timeout(t)

    ch := make(chan string)
    go readword(ch)

    select {
    case word := <-ch:
        fmt.Println("Received", word)
    case <-t:
        fmt.Println("Timeout.")
    }
}

Testowanie

Pakiet testowy zapewnia obsługę automatycznego testowania pakietów go. Przykład funkcji docelowej:

func ExtractUsername(email string) string {
	at := strings.Index(email, "@")
	return email[:at]
}

Kod testowy (zauważ, że w Go brakuje słowa kluczowego Assert; testy na żywo w <filename>_test.go w tym samym pakiecie):

import (
    "testing"    
)

func TestExtractUsername(t *testing.T) {
	t.Run("withoutDot", func(t *testing.T) {
		username := ExtractUsername("r@google.com")
		if username != "r" {
			t.Fatalf("Got: %v\n", username)
		}
	})

	t.Run("withDot", func(t *testing.T) {
		username := ExtractUsername("jonh.smith@example.com")
		if username != "jonh.smith" {
			t.Fatalf("Got: %v\n", username)
		}
	})

}

Możliwe jest równoległe prowadzenie testów.

Aplikacja internetowa

Pakiet net/http zapewnia obsługę tworzenia aplikacji internetowych.

Ten przykład pokaże "Witaj świecie!" kiedy odwiedzany jest localhost:8080.

package main

import (
    "fmt"
    "log"
    "net/http"    
)

func helloFunc(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello world!")
}

func main() {
    http.HandleFunc("/", helloFunc)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Aplikacje

Niektóre godne uwagi aplikacje open-source napisane w Go obejmują:

  • Caddy , serwer WWW typu open source HTTP/2 z automatyczną obsługą HTTPS
  • CockroachDB , open source, łatwa do przetrwania, silnie spójna, skalowalna baza danych SQL
  • Consul , oprogramowanie do wykrywania usług w oparciu o DNS i zapewniające rozproszone przechowywanie, segmentację i konfigurację kluczowych wartości.
  • Docker , zestaw narzędzi do wdrażania kontenerów Linux
  • EdgeX , niezależna od dostawców platforma open-source hostowana przez Linux Foundation , zapewniająca wspólną strukturę dla przemysłowego przetwarzania brzegowego IoT
  • Hugo , generator stron statycznych
  • InfluxDB , baza danych typu open source przeznaczona specjalnie do obsługi danych szeregów czasowych o wysokiej dostępności i wysokich wymaganiach dotyczących wydajności
  • InterPlanetary File System , adresowalny protokół hipermedialny peer-to-peer
  • Juju , narzędzie do aranżacji usług firmy Canonical , zajmujące się pakowaniem Ubuntu Linux
  • System zarządzania kontenerami Kubernetes
  • Po pierwsze, implementacja Bitcoin Lightning Network
  • Mattermost , system czatu zespołowego
  • NATS Messaging , system przesyłania wiadomości o otwartym kodzie źródłowym zawierający podstawowe zasady projektowania dotyczące wydajności, skalowalności i łatwości użytkowania
  • OpenShift , platforma przetwarzania w chmurze jako usługa firmy Red Hat
  • Rclone , program wiersza poleceń do zarządzania plikami w chmurze i innych usługach o wysokim opóźnieniu
  • Snappy , menedżer pakietów dla Ubuntu Touch opracowany przez Canonical
  • Syncthing , aplikacja klient/serwer do synchronizacji plików o otwartym kodzie źródłowym
  • Terraform , narzędzie typu open source do obsługi wielu infrastruktury chmurowej firmy HashiCorp
  • TiDB , rozproszona baza danych HTAP typu open source zgodna z protokołem MySQL firmy PingCAP

Inne godne uwagi firmy i witryny korzystające z Go (zazwyczaj razem z innymi językami, nie tylko) obejmują:

  • Cacoo , za renderowanie strony pulpitu nawigacyjnego użytkownika i mikrousługi za pomocą Go i gRPC
  • Chango , firma zajmująca się reklamą programistyczną, używa Go w swoich systemach licytacji w czasie rzeczywistym
  • Cloud Foundry , platforma jako usługa
  • Cloudflare , za ich proxy kodujące delta Railgun, ich rozproszoną usługę DNS, a także narzędzia do kryptografii, rejestrowania, przetwarzania strumieniowego i uzyskiwania dostępu do witryn SPDY
  • Container Linux (dawniej CoreOS), system operacyjny oparty na systemie Linux, który wykorzystuje kontenery Docker i kontenery rkt
  • Usługi Couchbase , zapytań i indeksowania w ramach Couchbase Server
  • Dropbox , który przeprowadził migrację niektórych kluczowych komponentów z Pythona do Go
  • Ethereum The Go-ethereum realizacja Ethereum Wirtualnej blockchain maszyna do Ether kryptowaluta
  • Gitlab , a oparte na sieci Web devops cyklu życia narzędzie, które dostarcza Git - repozytorium , wiki , śledzenia zgłoszeń , ciągłej integracji , wdrażania funkcje rurociągów
  • Google , dla wielu projektów, w szczególności serwera pobierania dl.google.com
  • Heroku , dla Doozer, usługa zamka
  • Hyperledger Fabric , projekt księgi rozproszonej o otwartym kodzie źródłowym, skoncentrowany na przedsiębiorstwach
  • MongoDB , narzędzia do administrowania instancjami MongoDB
  • Netflix za dwie części swojej architektury serwerowej
  • Nutanix , dla różnych mikrousług w systemie Enterprise Cloud OS
  • Plug.dj , interaktywna witryna społecznościowa do strumieniowego przesyłania muzyki
  • SendGrid , transakcyjna usługa dostarczania i zarządzania pocztą e-mail z siedzibą w Boulder w stanie Kolorado.
  • SoundCloud , dla „dziesiątek systemów”
  • Splice , dla całego zaplecza (API i parserów) ich internetowej platformy współpracy muzycznej
  • ThoughtWorks , niektóre narzędzia i aplikacje do ciągłego dostarczania i wiadomości błyskawicznych (CoyIM)
  • Twitch , za system czatu oparty na IRC (przeniesiony z Pythona)
  • Uber , do obsługi dużej liczby zapytań opartych na geofence


Zobacz także powiązane zapytanie do Wikidanych .

Przyjęcie

System interfejsu i celowe pomijanie dziedziczenia zostały pochwalone przez Michele Simionato, który porównał te cechy do cech Standard ML , nazywając to „szkodą, że żaden popularny język nie podąża [tę] konkretną drogą”.

Dave Astels z Engine Yard napisał:

Go jest niezwykle łatwe do zanurzenia. Istnieje minimalna liczba podstawowych pojęć językowych, a składnia jest czysta i zaprojektowana tak, aby była jasna i jednoznaczna. Go jest wciąż eksperymentalne i wciąż trochę szorstkie na brzegach.

Go został nazwany Językiem Programowania Roku przez TIOBE Programming Community Index w pierwszym roku 2009, za większy 12-miesięczny wzrost popularności (w ciągu zaledwie 2 miesięcy, po jego wprowadzeniu w listopadzie) niż jakikolwiek inny język w tym roku. i osiągnął 13. miejsce do stycznia 2010 r., wyprzedzając znane języki, takie jak Pascal . Do czerwca 2015 r. jego ranking spadł poniżej 50. miejsca w indeksie, plasując go niżej niż COBOL i Fortran . Jednak od stycznia 2017 r. jego ranking wzrósł na 13. miejsce, wskazując na znaczny wzrost popularności i adopcji. Go został nagrodzony językiem programowania TIOBE roku 2016.

Bruce Eckel stwierdził:

Złożoność C++ (jeszcze większa złożoność została dodana w nowym C++) i wynikający z niej wpływ na produktywność nie są już uzasadnione. Wszystkie obręcze, przez które programista C++ musiał przeskoczyć, aby użyć języka kompatybilnego z C, nie mają już sensu - to tylko strata czasu i wysiłku. Go ma o wiele więcej sensu w przypadku klasy problemów, które pierwotnie miał rozwiązać C++.

Ocena języka i jego implementacji gc z 2011 r. w porównaniu z C++ ( GCC ), Javą i Scala przez inżyniera Google stwierdziła:

Go oferuje ciekawe funkcje językowe, które pozwalają również na zwięzłą i ustandaryzowaną notację. Kompilatory dla tego języka są wciąż niedojrzałe, co odzwierciedla zarówno wydajność, jak i rozmiary binarne.

—  R. Hundt

Ocena została odrzucona przez zespół programistów Go. Ian Lance Taylor, który poprawił kod Go dla artykułu Hundta, nie był świadomy zamiaru opublikowania swojego kodu i mówi, że jego wersja „nigdy nie miała być przykładem idiomatycznego lub wydajnego Go”; Russ Cox następnie zoptymalizował kod Go, a także kod C++ i sprawił, że kod Go działał nieco szybciej niż C++ io więcej niż rząd wielkości szybciej niż kod w artykule.

Spór o nazwę

10 listopada 2009 roku, w dniu powszechnej premiery języka, Francis McCabe, twórca Go! język programowania (zwróć uwagę na wykrzyknik), poprosił o zmianę nazwy języka Google, aby uniknąć pomyłek z jego językiem, nad którym pracował przez 10 lat. McCabe wyraził obawy, że „wielki facet” przetoczy się nad nim, a obawa ta odbiła się echem wśród ponad 120 programistów, którzy skomentowali w oficjalnym wątku Google'a, mówiąc, że powinni zmienić nazwę, a niektórzy nawet mówili o problemie jest sprzeczne z mottem Google: nie bądź zły .

12 października 2010 r. problem został zamknięty przez dewelopera Google Russa Coxa (@rsc) z niestandardowym statusem „Niefortunny”, któremu towarzyszył następujący komentarz:

„Istnieje wiele produktów i usług komputerowych o nazwie Go. W ciągu 11 miesięcy od naszego wydania nastąpiło minimalne zamieszanie w tych dwóch językach”.

Krytyka

Krytycy Go twierdzą, że:

  • Brak polimorfizmu parametrycznego dla programowania generycznego prowadzi do duplikacji kodu lub niebezpiecznych konwersji typów i zakłócania szczegółowości.
  • Zero Go w połączeniu z brakiem typów algebraicznych prowadzi do trudności w obsłudze błędów i przypadków bazowych .
  • Go nie pozwala na pojawienie się nawiasu otwierającego w osobnym wierszu, co zmusza wszystkich programistów Go do używania tego samego stylu nawiasu.
  • Semantyka plików w standardowej bibliotece Go jest w dużej mierze oparta na semantyce POSIX i nie jest dobrze odwzorowana na platformę Windows . Zauważ, że ten problem nie dotyczy Go, ale inne języki programowania rozwiązały go za pomocą dobrze zdefiniowanych standardowych bibliotek. Autor twierdzi również, że prostota Go jest iluzją i że aby rozwiązać problemy świata rzeczywistego, biblioteki z zaskakująco dużymi zależnościami muszą zostać wciągnięte, aby rozwiązać coś tak prostego, jak implementacja monotonicznie rosnącej funkcji czasu.

Badanie pokazuje, że błędy współbieżności przy przekazywaniu wiadomości są równie łatwe, jak w przypadku pamięci współdzielonej, a czasem nawet więcej.

Zobacz też

Uwagi

Bibliografia

funkyprogrammer .uk /concurrency-in-go-programming-language /

Dalsza lektura

Zewnętrzne linki