Go Channels Tutorial

w tym samouczku przyjrzymy się, w jaki sposób można korzystać z kanałów w aplikacjach opartych na Go.

Kanały to rury, które łączą się między goroutines w twoich aplikacjach Go, które umożliwiają komunikację, a następnie przekazywanie wartości do i ze zmiennych.

są niezwykle poręczne i mogą pomóc w tworzeniu niesamowicie wydajnych,wysoce równoczesnych aplikacji W Go przy minimalnym zamieszaniu w porównaniu z innymi językami programowania. Bynajmniej nie był to przypadek, gdy projektując język, główni programiści zdecydowali, że chcą współbieżności w swoim języku, aby być obywatelem pierwszej klasy i aby praca z nim była tak prosta, jak to możliwe, bez posuwania się za daleko i nie pozwalając programistom na swobodę pracy.

umiejętność tworzenia systemów współbieżnych tak łatwo przyciągnęła mnie do języka i muszę powiedzieć, że do tej pory było to absolutne światło.

Uwaga – polecam rzucić okiem na mój inny samouczek na goroutines, jeśli chcesz dowiedzieć się więcej o goroutines.

pod koniec tego tutoriala będziesz:

  • mieć solidne zrozumienie teorii kanałów
  • być w stanie tworzyć proste równoległe aplikacje Go, które używają kanałów

wymagania wstępne

aby ukończyć ten samouczek, musisz spełnić następujące wymagania:

  • będziesz musiał Go zainstalować na swoim komputerze.

samouczek wideo

jeśli chcesz, ten samouczek jest dostępny w formacie wideo.

teoria

idea kanałów nie jest niczym nowym, ponieważ jak wiele współbieżności Go, koncepcje te zostały wyprowadzone z takich jak Hoare ’ scommunicating Sequential Processes (1978), w skrócie CSP, a nawet z książek strzeżonych poleceń Dijkstry (1975).

jednak twórcy Go postawili sobie za cel przedstawienie tych koncepcji w możliwie prosty sposób, aby umożliwić programistom tworzenie lepszych, bardziej poprawnych, wysoce współbieżnych aplikacji.

prosty przykład

zacznijmy od tego, jak możemy zbudować naprawdę prosty przykład tego, jak to działa w Go. Najpierw utworzymy funkcję, która odejdzie i obliczy wartość anarbitryczną, losową i przekaże ją z powrotem do zmiennej kanału o nazwievalues:

główna.idź

wykreślmy co tu się stało. W naszej funkcji main() nazwaliśmyvalues := make(chan int), to wywołanie skutecznie stworzyło nasz nowy kanał, abyśmy mogli później użyć go w naszej CalculateValue goroutine.

Uwaga-użyliśmy make podczas tworzenia instancji naszego kanału values jako, podobnie jak Mapy i plasterki, kanały muszą być utworzone przed użyciem.

po utworzeniu kanału, zadzwoniliśmy do defer close(values), co spowodowało zamknięcie naszego kanału do zakończenia wykrywania funkcji main(). Jest to zazwyczaj uważane za najlepszą praktykę, aby zapewnić porządek po sobie.

po naszym telefonie na defer, zaczynamy nasz pojedynczy goroutine:CalculateValue(values) przechodząc do naszego nowo utworzonego kanału values jako jego parametr. W ramach naszej funkcji CalculateValueobliczamy pojedynczą wartość losową z zakresu 1-10, wypisujemy ją, a następnie wysyłamy tę wartość do naszego kanału values, wywołując values <- value.

Wracając do naszej funkcji main(), wywołujemy value := <-values, która odbiera wartość z naszego kanału values.

Uwaga – zauważ, że kiedy uruchamiamy ten program, nie działa on natychmiast. Dzieje się tak, ponieważ akt wysyłania i odbierania z kanału są blokowane. Nasza funkcja main() blokuje się, dopóki nie otrzyma wartości z ourchannel.

po wykonaniu tego kodu powinieneś zobaczyć, że wyjście wygląda mniej więcej tak:

$ go run main.goGo Channel TutorialCalculated Random Value: {} 77

Streszczenie:

myChannel := make(chan int) – tworzy myChannel, który jest kanałem typuint

channel <- value – wysyła wartość do kanału

value := <- channel – odbiera wartość z kanału

więc tworzenie i używanie kanałów w programach Go wygląda fairlystraightforward, ale co z bardziej złożonymi scenariuszami?

kanały Niebuforowane

Korzystanie z tradycyjnego channel w obrębie Twoich urządzeń może czasami prowadzić do zachowań, których możesz się nie spodziewać. W przypadku tradycyjnych kanałówunbuffered, gdy jeden goroutine wyśle wartość do tego kanału, goroutine będzie następnie blokował, dopóki wartość nie zostanie odebrana z kanału.

zobaczmy to w prawdziwym przykładzie. Jeśli przyjrzymy się poniższemu kodowi, jest on bardzo podobny do kodu, który mieliśmy wcześniej. Jednak rozszerzyliśmy naszą funkcjęCalculateValue(), aby wykonać fmt.Println po wysłaniu jej obliczonej wartości do kanału.

w naszej funkcji main() dodaliśmy drugie wywołanie dogo CalculateValue(valueChannel) więc powinniśmy spodziewać się 2 wartości wysyłanych do tego kanału w bardzo szybkim tempie.

główna.idź

jednak po uruchomieniu tego, powinieneś zobaczyć, że tylko nasze pierwsze polecenie goroutines ’ finalprint jest rzeczywiście wykonywane:

go run main.goGo Channel TutorialCalculated Random Value: {} 1Calculated Random Value: {} 71Only Executes after another goroutine performs a receive on the channel

powodem tego jest to, że nasze wywołanie c <- value zostało zablokowane w naszym secondgoroutine, a następnie funkcja main() kończy jego wykonanie, zanim nasza druga goroutine otrzyma szansę na zakończenie własnego wykonania.

kanały buforowane

sposobem obejścia tego zachowania blokującego jest użycie czegoś o nazwie kanał buforowany. Te buforowane kanały są zasadniczo kolejkami o danej wielkości, które mogą być używane do komunikacji międzygórskiej. Aby utworzyć kanał niebuforowany w przeciwieństwie do kanału niebuforowanego, podajemy polecenie make :

bufferedChannel := make(chan int, 3)

zmieniając to na kanał buforowany, nasza operacja wysyłania, c <- value tylko blokuje się w naszych goroutines powinien kanał być pełny.

zmodyfikujmy nasz istniejący program tak, aby korzystał z kanału buforowanego i przyjrzyjmy się wyjściu. Zauważ, że dodałem wywołanie dotime.Sleep() na dole naszej funkcji main(), aby leniwie zablokować naszą funkcję main() na tyle, aby umożliwić wykonanie goroutines.

główna.idź

teraz, kiedy wykonujemy to, powinniśmy zobaczyć, że nasz drugi goroutine nie kontynuuje jego wykonywania, niezależnie od tego, że drugi odbiór nie został wywołany w naszej funkcji main(). Dzięki time.Sleep() możemy wyczyścićpoznaj różnicę między kanałami niebuforowanymi i ich blokowaniem, a kanałami buforowanymi i ich nieblokującą (gdy nie są pełne) naturą.

Go Channel TutorialCalculated Random Value: {} 1Calculated Random Value: {} 77This executes regardless as the send is now non-blockingThis executes regardless as the send is now non-blocking

wniosek

w tym dość długim samouczku udało nam się dowiedzieć o różnych typach kanałów w Go. Odkryliśmy różnice między kanałami buforowanymi i niebuforowanymi oraz jak możemy je wykorzystać w naszych programach go.

Jeśli podobał Ci się ten samouczek, daj mi znać w sekcji poniżej. Jeśli masz jakieś sugestie, co mógłbym zrobić lepiej, chciałbym je usłyszeć w sekcji komentarzy poniżej!

Czytaj dalej

Jeśli podobał Ci się ten artykuł i chcesz dowiedzieć się więcej o pracy z Concurrencyin Go, to polecam sprawdzić nasze inne artykuły na temat współbieżności:

  • Go Mutex Tutorial
  • go Goroutines Tutorial
  • Go sync.Waitgroup Tutorial

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.

Previous post system biblioteczny Hrabstwa Brunswick
Next post należy malować lub bejcować szafki? Plusy i minusy każdego