Go Channels Tutorial

i denna handledning kommer vi att titta på hur du kan användakanaler inom dina Go-baserade applikationer.

kanaler är rör som länkar mellan goroutines inom dina Go-baseradeapplikationer som tillåter kommunikation och därefter överföring av värden till och från variabler.

de är otroligt praktiska och kan hjälpa dig att skapa otroligt högpresterande,mycket samtidiga applikationer I Go med minimal krångel jämfört med andraprogrammeringsspråk. Detta var ingalunda en lyckträff, när man utformar thelanguage, core utvecklare beslutat att de ville samtidighet inom theirlanguage att vara en förstklassig medborgare och att göra det så enkelt att arbeta med aspossible, utan att gå för långt och inte tillåta utvecklare friheten theyneed att arbeta i.

förmågan att skapa samtidiga system så lätt är något som drog mig till språket i första hand, och jag måste säga att det har varit ett absolutedelight hittills.

OBS – Jag skulle rekommendera att ta en titt på min andra handledning ongoroutines om du vill learnmore om goroutines.

mål

i slutet av denna handledning kommer du att:

  • ha en gedigen förståelse för teorin bakom kanaler
  • kunna skapa enkla samtidiga Go-applikationer som använder kanaler

förutsättningar

för att slutföra denna handledning måste du ha uppfyllt följandeprerequisites:

  • du kommer att behöva Go installerat på din maskin.

Video Tutorial

om du vill är denna handledning tillgänglig i videoformat.

teorin

tanken på kanaler är inte något nytt, som liksom många av Go: s samtidighetsfunktioner har dessa begrepp tagits fram från sådana som Hoare ’communicating Sequential Processes (1978), CSP för kort och till och med från thelikes of Dijkstra’ s guarded commands (1975).

utvecklarna av Go har dock gjort det till sitt uppdrag att presentera dessabegrepp på ett enkelt sätt som möjligt för programmerare att skapabättre, mer korrekta, mycket samtidiga applikationer.

ett enkelt exempel

Låt oss börja med att se hur vi kan bygga upp ett riktigt enkelt exempel på hurdetta fungerar i Go. Vi skapar först en funktion som går bort och beräknar anarbitrary, slumpmässigt värde och skickar tillbaka det till en kanalvariabel som hetervalues:

main.gå

Låt oss disect vad som hände här. I vår main() – funktion kallade vivalues := make(chan int), detta samtal skapade effektivt vår nya kanal så att vi senare kunde använda den inom vår CalculateValue goroutine.

Obs – vi använde make när instantiating vår values kanal som, likemaps och skivor, kanaler måste skapas före användning.

efter att vi skapat ut kanal, vi kallade sedan defer close(values) somdefered stängningen av vår kanal fram till slutet av vår main() funktionsexekution. Detta anses vanligtvis vara bästa praxis för att säkerställa att vi städar oss själva.

efter vårt samtal till defer fortsätter vi med att sparka av vår enda goroutine:CalculateValue(values) passerar i vår nyskapade values kanal som itsparameter. Inom vår CalculateValue – funktion beräknar vi en enda randomvalue mellan 1-10, skriver ut detta och skickar sedan detta värde till vår valueskanal genom att ringa values <- value.

hoppa tillbaka till vår main() – funktion, vi ringer sedan value := <-values som får ett värde från vår values – kanal.

Obs-Lägg märke till hur när vi kör det här programmet, det inte omedelbartterminera. Detta beror på att handlingen att skicka till och ta emot från en kanalblockerar. Vår main() – funktion blockerar tills den får ett värde från vårkanal.

vid körning av denna kod bör du se utmatningen se ut så här:

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

sammanfattning:

myChannel := make(chan int) – skapar myChannel som är en kanal av typint

channel <- value – skickar ett värde till en kanal

value := <- channel – tar emot ett värde från en kanal

så, instantiating och använda kanaler i dina Go-program ser fairlystraightforward hittills, men hur är det i mer komplexa scenarier?

obuffrade kanaler

att använda en traditionell channel inom dina goroutiner kan ibland leda tillproblem med beteende som du kanske inte riktigt förväntar dig. Med traditionella unbuffered kanaler, när en goroutine skickar ett värde till denna kanal,kommer goroutine därefter att blockera tills värdet tas emot från kanalen.

Låt oss se detta i ett riktigt exempel. Om vi tittar på koden nedan är det väldigt mycketliknar koden som vi tidigare hade. Vi har dock utökat vårCalculateValue() – funktion för att utföra ett fmt.Println efter att den har skickat det slumpmässigt beräknade värdet till kanalen.

i vår main() – funktion har vi lagt till ett andra samtal tillgo CalculateValue(valueChannel) så vi borde förvänta oss 2 värden som skickas till thischannel i mycket snabb följd.

Huvud.go

men när du kör detta bör du se att endast våra första goroutines finalprint-uttalande faktiskt körs:

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

anledningen till detta är att vår uppmaning till c <- value har blockerats i vår secondgoroutine och därefter avslutar funktionen main() att den är exekverad innan vår andra goroutine får en chans att slutföra sin egen exekvering.

buffrade kanaler

sättet att komma runt detta blockeringsbeteende är att använda något som kallas abuffered channel. Dessa buffrade kanaler är i huvudsak köer av en viss storleksom kan användas för kommunikation över goroutine. För att skapa missbrukad kanal i motsats till en obuffrad kanal levererar vi ett kapacitetsargument till vårt make – kommando:

bufferedChannel := make(chan int, 3)

genom att ändra detta till en buffrad kanal, blockerar vår sändningsoperation, c <- value endast inom våra goroutiner om kanalen är full.

låt oss ändra vårt befintliga program för att använda en buffrad kanal och ta en titt påutgången. Lägg märke till att jag har lagt till ett samtal till time.Sleep() längst ner i vårmain() – funktion för att enkelt blockera vår main() – funktion tillräckligt för att tillåta våra goroutiner att slutföra utförandet.

Huvud.gå

nu, när vi utför detta, bör vi se att vår andra goroutine gör det fortsätt att utföra det oavsett det faktum att en andra mottagning inte har kallats i vår main() – funktion. Tack vare time.Sleep() kan vi tydligt se skillnaden mellan obuffrade kanaler och deras blockerande natur och våra drabbade kanaler och deras icke-blockerande (när de inte är fulla) 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

slutsats

så i denna ganska långa handledning lyckades vi lära oss om de olikasärskilda typer av kanaler inom Go. Vi upptäckte skillnaderna mellan bothbuffered och obuffrade kanaler och hur vi kunde använda dem till vår fördel inom våra samtidiga go-program.

om du gillade den här handledningen, var god och låt mig veta i kommentarfältet nedan. Om du har några förslag på vad jag kunde göra bättredå skulle jag gärna höra dem i kommentarfältet nedan!

Vidare läsning

om du gillade den här artikeln och vill lära dig mer om att arbeta med Samtidigtin Go, rekommenderar jag att du kolla in våra andra artiklar om samtidighet:

  • gå mutex handledning
  • gå Goroutines handledning
  • gå sync.WaitGroup Tutorial

Lämna ett svar

Din e-postadress kommer inte publiceras.

Previous post Brunswick County Library System
Next post ska du måla eller fläcka skåp? Fördelar och nackdelar med varje