Tak, fordi du abonnerer

introduktion

da jeg begyndte at arbejde med Go ‘ s kanaler for første gang, begik jeg fejlen ved at tænke på kanaler som en datastruktur. Jeg så kanaler som en kø, der gav automatisk synkroniseret adgang mellem goroutines. Denne strukturelle forståelse fik mig til at skrive en masse dårlig og kompliceret samtidig kode.

jeg lærte over tid, at det er bedst at glemme, hvordan kanaler er struktureret og fokusere på, hvordan de opfører sig. Så nu når det kommer til kanaler, tænker jeg på en ting: signalering. En kanal tillader en goroutine at signalere en anden goroutine om en bestemt begivenhed. Signalering er kernen i alt, hvad du skal gøre med kanaler. At tænke på kanaler som en signalmekanisme giver dig mulighed for at skrive bedre kode med veldefineret og mere præcis opførsel.

for at forstå, hvordan signalering fungerer, skal vi forstå dens tre attributter:

  • garanti for levering
  • stat
  • med eller uden Data

disse tre attributter arbejder sammen om at skabe en designfilosofi omkring signalering. Når jeg har diskuteret disse attributter, vil jeg give et antal kodeeksempler, der viser signalering med disse anvendte attributter.

leveringsgaranti

Leveringsgarantien er baseret på et spørgsmål: “har jeg brug for en garanti for, at signalet sendt af en bestemt goroutine er modtaget?”

med andre ord, givet dette eksempel i notering 1:

notering 1

01 go func() {02 p := <-ch // Receive03 }()0405 ch <- "paper" // Send

har den afsendende goroutine brug for en garanti for, at paper, der sendes over kanalen på linje 05, blev modtaget af goroutine på linje 02, før den gik videre?

baseret på svaret på dette spørgsmål vil du vide, hvilken af de to typer kanaler der skal bruges: Ubufferet eller bufferet. Hver kanal giver en anden adfærd omkring garantier for levering.

Figur 1 : leveringsgaranti

leveringsgaranti

garantier er vigtige, og hvis du ikke tror det, har jeg masser af ting, jeg vil sælge dig. Selvfølgelig prøver jeg at lave en vittighed, men bliver du ikke nervøs, når du ikke har garantier i livet? At have en stærk forståelse af, om du har brug for en garanti, er afgørende, når du skriver samtidige programmer. Når vi fortsætter, lærer du, hvordan du beslutter dig.

tilstand

en kanals opførsel påvirkes direkte af dens nuværende tilstand. En kanals tilstand kan være nul, åben eller lukket.

Liste 2 nedenfor viser, hvordan man erklærer eller placerer en kanal i hver af disse tre stater.

Liste 2

// ** nil channel// A channel is in a nil state when it is declared to its zero valuevar ch chan string// A channel can be placed in a nil state by explicitly setting it to nil.ch = nil// ** open channel// A channel is in a open state when it's made using the built-in function make.ch := make(chan string) // ** closed channel// A channel is in a closed state when it's closed using the built-in function close.close(ch)

staten bestemmer, hvordan send og modtag operationer opfører sig.

signaler sendes og modtages via en kanal. Sig ikke læse / skrive, fordi kanaler ikke udfører I / O.

figur 2 : tilstand

tilstand

når en kanal er i nul-tilstand, blokeres enhver Send eller modtag forsøg på kanalen. Når en kanal er i åben tilstand, kan signaler sendes og modtages. Når en kanal placeres i en lukket tilstand, kan signaler ikke længere sendes, men det er stadig muligt at modtage signaler.

disse tilstande vil give de forskellige adfærd, du har brug for til de forskellige situationer, du støder på. Når du kombinerer tilstand med garanti for levering, kan du begynde at analysere de omkostninger/fordele, du pådrager dig som følge af dine designvalg. I mange tilfælde vil du også være i stand til hurtigt at få øje på fejl bare ved at læse koden, fordi du forstår, hvordan kanalen skal opføre sig.

med og uden Data

den sidste signalattribut, der skal tages i betragtning, er, om du skal signalere med eller uden data.

du signalerer med data ved at udføre en send på en kanal.

Liste 3

01 ch <- "paper"

når du signalerer med data, er det normalt fordi:

  • en goroutine bliver bedt om at starte en ny opgave.
  • en goroutine rapporterer tilbage et resultat.

du signalerer uden data ved at lukke en kanal.

liste 4

01 close(ch)

når du signalerer uden data, er det normalt fordi:

  • en goroutine bliver bedt om at stoppe, hvad de laver.
  • en goroutine rapporterer tilbage, at de er færdige uden resultat.
  • en goroutine rapporterer, at den har afsluttet behandlingen og lukket ned.

der er undtagelser fra disse regler, men dette er de største brugssager og dem, vi vil fokusere på i dette indlæg. Jeg vil betragte undtagelser fra disse regler som en indledende kodelugt.

en fordel ved signalering uden data er, at en enkelt goroutine kan signalere mange goroutiner på en gang. Signalering med data er altid en 1 til 1 udveksling mellem goroutiner.

signalering med Data

når du skal signalere med data, er der tre kanalkonfigurationsmuligheder, du kan vælge afhængigt af den type garanti, du har brug for.

figur 3 : Signalering med Data

de tre kanalindstillinger er Unbuffered, Buffered > 1 eller Buffered =1.

  • garanti

    • en kanal uden buffer giver dig en garanti for, at et signal, der sendes, er modtaget.
      • fordi modtagelsen af signalet sker, før sendingen af signalet er afsluttet.
  • ingen garanti

    • en Bufferkanal af størrelse > 1 giver dig ingen garanti for, at et signal, der sendes, er modtaget.
      • fordi sendingen af signalet sker, før modtagelsen af signalet er afsluttet.
  • forsinket garanti

    • en bufret kanal af størrelse =1 giver dig en forsinket garanti. Det kan garantere, at det tidligere signal, der blev sendt, er modtaget.
      • fordi modtagelsen af det første Signal sker, før afsendelsen af det andet Signal er afsluttet.

bufferens størrelse må aldrig være et tilfældigt tal, det skal altid beregnes for en veldefineret begrænsning. Der er ingen uendelighed i computing, alt skal have en veldefineret begrænsning, uanset om det er tid eller rum.

signalering uden Data

signalering uden data er hovedsageligt forbeholdt annullering. Det giver en goroutine mulighed for at signalere en anden goroutine for at annullere, hvad de laver, og gå videre. Annullering kan implementeres ved hjælp af både Unbuffered og Buffered kanaler, men ved hjælp af en Buffered kanal, når ingen data vil blive sendt, er en kode lugt.

figur 4 : Signalering uden Data

den indbyggede funktion close bruges til at signalere uden data. Som forklaret ovenfor i Tilstandsafsnittet kan du stadig modtage signaler på en kanal, der er lukket. Faktisk vil enhver modtagelse på en lukket kanal ikke blokere, og modtageoperationen vender altid tilbage.

i de fleste tilfælde vil du bruge standardbiblioteket context – pakken til at implementere signalering uden data. Pakken context bruger en Unbuffered kanal nedenunder til signalering og den indbyggede funktion close til at signalere uden data.

hvis du vælger at bruge din egen kanal til annullering i stedet for kontekstpakken, skal din kanal være af typen chan struct{}. Det er den nul-plads, idiomatisk måde at indikere en kanal, der kun bruges til signalering.

scenarier

med disse attributter på plads er den bedste måde at forstå, hvordan de fungerer i praksis, at køre gennem en række kodescenarier. Jeg kan godt lide at tænke på goroutiner som mennesker, når jeg læser og skriver kanalbaseret kode. Denne visualisering hjælper virkelig, og jeg vil bruge den som en hjælp nedenfor.

Signal med data – garanti – ikke-bufferede kanaler

når du har brug for at vide, at et signal, der sendes, er modtaget, kommer to scenarier i spil. Disse venter på opgaven og venter på resultatet.

Scenario 1 – Vent til opgave

tænk på at være leder og ansætte en ny medarbejder. I dette scenario vil du have din nye medarbejder til at udføre en opgave, men de skal vente, indtil du er klar. Dette skyldes, at du skal give dem et stykke papir, før de starter.

Liste 5
https://play.golang.org/p/BnVEHRCcdh

01 func waitForTask() {02 ch := make(chan string)0304 go func() {05 p := <-ch0607 // Employee performs work here.0809 // Employee is done and free to go.10 }()1112 time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)1314 ch <- "paper"15 }

på linje 02 i notering 5 oprettes en Unbuffered kanal med attributten, at string data vil blive sendt med signalet. Derefter på linje 04, En medarbejder ansættes og får besked på at vente på dit signal på linje 05, før de udfører deres arbejde. Linje 05 er den kanal, der modtager, hvilket får medarbejderen til at blokere, mens han venter på det stykke papir, du vil sende. Når papiret er modtaget af medarbejderen, udfører medarbejderen arbejdet og er derefter færdig og fri til at gå.

du som leder arbejder sideløbende med din nye medarbejder. Så når du ansætter medarbejderen på linje 04, finder du dig selv (på linje 12) gør hvad du skal gøre for at fjerne blokeringen og signalere medarbejderen. Bemærk, det var ukendt, hvor lang tid det ville tage at forberede dette stykke papir, du skal sende.

til sidst er du klar til at signalere medarbejderen. På linje 14 udfører du et signal med data, hvor dataene er det stykke papir. Da der bruges en ikke-bufferet kanal, får du en garanti for, at medarbejderen har modtaget papiret, når din send-operation er afsluttet. Modtagelsen sker før afsendelsen.

teknisk set er alt, hvad du ved, at medarbejderen har papiret, når din kanaludsendelsesoperation er afsluttet. Efter begge kanaloperationer kan planlæggeren vælge at udføre enhver erklæring, den ønsker. Den næste kodelinje, der udføres enten af dig eller medarbejderen, er ikke-bestemmende. Dette betyder, at brug af trykte udsagn kan narre dig om rækkefølgen af ting.

Scenario 2 – Vent på resultatet

i dette næste scenario er tingene vendt. Denne gang vil du have din nye medarbejder til at udføre en opgave straks, når de ansættes, og du skal vente på resultatet af deres arbejde. Du skal vente, fordi du har brug for papiret fra dem, før du kan fortsætte.

Liste 6
https://play.golang.org/p/VFAWHxIQTP

01 func waitForResult() {02 ch := make(chan string)0304 go func() {05 time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)0607 ch <- "paper"0809 // Employee is done and free to go.10 }()1112 p := <-ch13 }

på linje 02 i notering 6 oprettes en Unbuffered kanal med attributten, at string data vil blive sendt med signalet. Derefter på linje 04 ansættes en medarbejder og sættes straks på arbejde. Når du ansætter medarbejderen på linje 04, finder du dig selv næste på linje 12 og venter på papirrapporten.

når arbejdet er afsluttet af medarbejderen på linje 05, sender de resultatet til dig på linje 07 ved at udføre en kanal send med data. Da dette er en Ubufferet kanal, sker modtagelsen før sendingen, og medarbejderen er garanteret, at du har modtaget resultatet. Når medarbejderen har denne garanti, er de færdige og fri til at gå. I dette scenario har du ingen anelse om, hvor lang tid det vil tage medarbejderen at afslutte opgaven.

Cost/Benefit

en ikke-bufferet kanal giver en garanti for, at et signal, der sendes, blev modtaget. Dette er fantastisk, men intet er gratis. Omkostningerne ved denne garanti er ukendt latenstid. I ventetiden på Opgavescenariet har medarbejderen ingen anelse om, hvor lang tid det vil tage for dig at sende det papir. I ventetiden på Resultatscenariet har du ingen anelse om, hvor lang tid det vil tage medarbejderen at sende dig det resultat.

i begge scenarier er denne ukendte latenstid noget, vi skal leve med, fordi garantien er påkrævet. Logikken fungerer ikke uden denne garanterede adfærd.

Signal med Data – Ingen garanti-bufrede kanaler >1

når du ikke behøver at vide, at der er modtaget et signal, der sendes, kommer disse to scenarier i spil: Fan Out and Drop.

en Bufferkanal har et veldefineret rum, der kan bruges til at gemme de data, der sendes. Så hvordan bestemmer du, hvor meget plads du har brug for? Besvar disse spørgsmål:

  • har jeg en veldefineret mængde arbejde, der skal udføres?
    • hvor meget arbejde er der?
  • hvis min medarbejder ikke kan følge med, kan jeg så kassere noget nyt arbejde?
    • hvor meget fremragende arbejde sætter mig i kapacitet?
  • hvilket risikoniveau er jeg villig til at acceptere, hvis mit program afsluttes uventet?
    • alt, der venter i bufferen, går tabt.

hvis disse spørgsmål ikke giver mening for den adfærd, du modellerer, er det en kodelugt, at brug af en bufret kanal, der er større end 1, sandsynligvis er forkert.

Scenario 1 – Fan out

et fan out mønster giver dig mulighed for at kaste et veldefineret antal medarbejdere på et problem, der arbejder samtidigt. Da du har en medarbejder til hver opgave, ved du nøjagtigt, hvor mange rapporter du vil modtage. Du kan sikre dig, at der er den rigtige mængde plads i din boks til at modtage alle disse rapporter. Dette har fordelen ved, at dine medarbejdere ikke behøver at vente på, at du indsender deres rapport. De har dog brug for at hver tage en tur placere rapporten i din kasse, hvis de ankommer til kassen på eller nær samme tid.

Forestil dig, at du er manager igen, men denne gang ansætter du et team af medarbejdere. Du har en individuel opgave, du vil have hver medarbejder til at udføre. Når hver enkelt medarbejder afslutter sin opgave, skal de give dig en papirrapport, der skal placeres i din kasse på dit skrivebord.

Liste 7
https://play.golang.org/p/8HIt2sabs_

01 func fanOut() {02 emps := 2003 ch := make(chan string, emps)0405 for e := 0; e < emps; e++ {06 go func() {07 time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)08 ch <- "paper"09 }()10 }1112 for emps > 0 {13 p := <-ch14 fmt.Println(p)15 emps--16 }17 }

på linje 03 i notering 7 oprettes en bufret kanal med attributten, at string data vil blive sendt med signalet. Denne gang oprettes kanalen med 20 buffere takket være emps – variablen, der er erklæret på linje 02.

mellem linjerne 05 til 10 ansættes 20 ansatte, og de kommer straks på arbejde. Du aner ikke, hvor længe hver medarbejder skal tage på linje 07. Så på linje 08 sender medarbejderne papirrapporten, men denne gang blokerer sendingen ikke for at vente på en modtagelse. Da der er plads i kassen til hver medarbejder, konkurrerer sendingen på kanalen kun med andre medarbejdere, der måske ønsker at sende deres rapport på eller nær samme tid.

koden mellem linjerne 12 til 16 er alt dig. Det er her, du venter på, at alle 20 medarbejdere afslutter deres arbejde og sender deres rapport. På linje 12, Du er i en løkke og på linje 13 Du er blokeret i en kanal modtager venter på dine rapporter. Når en rapport er modtaget, udskrives rapporten på linje 14, og den lokale tællervariabel reduceres for at indikere, at en medarbejder er færdig.

Scenario 2 – Drop

et drop mønster giver dig mulighed for at smide arbejde væk, når dine medarbejdere er på kapacitet. Dette har fordelen ved at fortsætte med at acceptere arbejde fra dine kunder og aldrig anvende modtryk eller forsinkelse i accept af dette arbejde. Nøglen her er at vide, hvornår du virkelig er i kapacitet, så du ikke under eller over forpligter dig til den mængde arbejde, du vil forsøge at få gjort. Normalt er integrationstest eller metrics det, du har brug for for at hjælpe dig med at identificere dette nummer.

Forestil dig, at du er leder igen, og du ansætter en enkelt medarbejder for at få arbejdet udført. Du har en individuel opgave, som medarbejderen skal udføre. Når medarbejderen afslutter deres opgave, er du ligeglad med at vide, at de er færdige. Alt, hvad der er vigtigt, er, om du kan eller ikke kan placere nyt arbejde i kassen. Hvis du ikke kan udføre sendingen, så ved du, at din boks er fuld, og medarbejderen er i kapacitet. På dette tidspunkt skal det nye arbejde kasseres, så tingene kan fortsætte.

Liste 8
https://play.golang.org/p/PhFUN5itiv

01 func selectDrop() {02 const cap = 503 ch := make(chan string, cap)0405 go func() {06 for p := range ch {07 fmt.Println("employee : received :", p)08 }09 }()1011 const work = 2012 for w := 0; w < work; w++ {13 select {14 case ch <- "paper":15 fmt.Println("manager : send ack")16 default:17 fmt.Println("manager : drop")18 }19 }2021 close(ch)22 }

på linje 03 i notering 8 oprettes en bufret kanal med attributten, at string data vil blive sendt med signalet. Denne gang oprettes kanalen med 5 buffere takket være cap – konstanten, der er erklæret på linje 02.

mellem linjerne 05 til 09 ansættes en enkelt medarbejder til at håndtere arbejdet. En for range bruges til kanalmodtagelsen. Hver gang et stykke papir modtages, behandles det på linje 07.

mellem linjerne 11 til 19 forsøger du at sende 20 stykker papir til din medarbejder. Denne gang bruges en select erklæring til at udføre sendingen inde i den første case på linje 14. Da default – klausulen bruges inde i select på linje 16, hvis sendingen vil blokere, fordi der ikke er mere plads i bufferen, afbrydes sendingen ved at udføre linje 17.

endelig på linje 21 kaldes den indbyggede funktion close mod kanalen. Dette vil signalere uden data til den medarbejder, de er færdige og fri til at gå, når de har afsluttet deres tildelte arbejde..

Cost/Benefit

en Bufferkanal større end 1 giver ingen garanti for, at et signal, der sendes, nogensinde modtages. Der er en fordel ved at gå væk fra denne garanti, som er den reducerede eller ingen latenstid i kommunikationen mellem to goroutiner. I fan out-scenariet er der en bufferplads for hver medarbejder, der sender en rapport. I Drop-scenariet måles bufferen for kapacitet, og hvis kapaciteten nås, tabes arbejdet, så tingene kan fortsætte med at bevæge sig.

i begge muligheder er denne mangel på garanti noget, vi skal leve med, fordi reduktionen i latenstid er vigtigere. Kravet om nul til minimum latenstid udgør ikke et problem for systemets overordnede logik.

Signal med Dataforsinket Garantibufret kanal 1

når det er nødvendigt at vide, om det forrige signal, der blev sendt, er modtaget, før der sendes et nyt signal, kommer scenariet vent på opgaver i spil.

Scenario 1 – Vent på opgaver

i dette scenario har du en ny medarbejder, men de skal gøre mere end blot en opgave. Du kommer til at fodre dem mange opgaver, den ene efter den anden. De skal dog afslutte hver enkelt opgave, før de kan starte en ny. Da de kun kan arbejde på en opgave ad gangen, kan der være latensproblemer mellem overdragelsen af arbejdet. Hvis latensen kunne reduceres uden at miste garantien for, at medarbejderen arbejder på den næste opgave, kan det hjælpe.

det er her en bufret kanal på 1 har fordel. Hvis alt kører i det forventede tempo mellem dig og medarbejderen, skal ingen af jer vente på den anden. Hver gang du sender et stykke papir, er bufferen tom. Hver gang din medarbejder rækker ud efter mere arbejde, er bufferen fuld. Det er en perfekt symmetri af arbejdsstrømmen.

den bedste del er dette. Hvis du på noget tidspunkt forsøger at sende et stykke papir, og du ikke kan, fordi bufferen er fuld, ved du, at din medarbejder har et problem, og du stopper. Det er her, den forsinkede garanti kommer ind. Når bufferen er tom, og du udfører sendingen, har du garanti for, at din medarbejder har taget det sidste stykke arbejde, du sendte. Hvis du udfører sendingen, og du ikke kan, har du den garanti, de ikke har.

notering 9
https://play.golang.org/p/4pcuKCcAK3

01 func waitForTasks() {02 ch := make(chan string, 1)0304 go func() {05 for p := range ch {06 fmt.Println("employee : working :", p)07 }08 }()0910 const work = 1011 for w := 0; w < work; w++ {12 ch <- "paper"13 }1415 close(ch)16 }

på linje 02 i notering 9 oprettes en bufret kanal af størrelse 1 med attributten, at string data vil blive sendt med signalet. Mellem linjerne 04 til 08 ansættes en enkelt medarbejder til at håndtere arbejdet. En for range bruges til kanalmodtagelsen. Hver gang et stykke papir modtages, behandles det på linje 06.

mellem linjerne 10 til 13 begynder du at sende dine opgaver til medarbejderen. Hvis din medarbejder kan køre så hurtigt som du kan sende, reduceres latensen mellem jer to. Men med hver send du udfører med succes, har du garanti for, at det sidste stykke arbejde, du har indsendt, bliver arbejdet på.

endelig på linje 15 kaldes den indbyggede funktion close mod kanalen. Dette vil signalere uden data til den medarbejder, de er færdige og fri til at gå. Det sidste stykke arbejde, du har indsendt, vil dog blive modtaget (skyllet), før for range afsluttes.

Signal uden Datakontekst

i dette sidste scenario vil du se, hvordan du kan annullere en kørende goroutine ved hjælp af en Context værdi fra context pakken. Alt dette fungerer ved at udnytte en ikke-bufferet kanal, der er lukket for at udføre et signal uden data.

du er leder en sidste gang, og du ansætter en enkelt medarbejder for at få arbejdet udført. Denne gang er du ikke villig til at vente på en ukendt tid for medarbejderen at afslutte. Du er på en diskret deadline, og hvis medarbejderen ikke er færdig i tide, er du ikke villig til at vente.

Liste 10
https://play.golang.org/p/6GQbN5Z7vC

01 func withTimeout() {02 duration := 50 * time.Millisecond0304 ctx, cancel := context.WithTimeout(context.Background(), duration)05 defer cancel()0607 ch := make(chan string, 1)0809 go func() {10 time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)11 ch <- "paper"12 }()1314 select {15 case p := <-ch:16 fmt.Println("work complete", p)1718 case <-ctx.Done():19 fmt.Println("moving on")20 }21 }

på linje 02 i notering 10 erklæres en varighedsværdi, der repræsenterer, hvor længe medarbejderen skal afslutte opgaven. Denne værdi bruges på linje 04 til at oprette en context.Context værdi med en timeout på 50 millisekunder. Funktionen WithTimeout fra pakken context returnerer en Context værdi og en annulleringsfunktion.

pakken context opretter en goroutine, der lukker den ikke-bufferede kanal, der er knyttet til Context – værdien, når varigheden er opfyldt. Du er ansvarlig for at kalde cancel – funktionen, uanset hvordan tingene viser sig. Dette vil rydde op i ting, der er oprettet til Context. Det er ok, at funktionen cancel kaldes mere end en gang.

på linje 05 udsættes funktionen cancel for at blive udført, når denne funktion ophører. På linje 07 oprettes en bufret kanal på 1, som vil blive brugt af medarbejderen til at sende dig resultatet af deres arbejde. Så på linje 09 til 12 er medarbejderen ansat og straks sat på arbejde. Du aner ikke, hvor lang tid det vil tage medarbejderen at afslutte.

mellem linjerne 14 til 20 bruger du select – erklæringen til at modtage på to kanaler. Modtag på linje 15, du venter på, at medarbejderen sender dig deres resultat. Modtag på linje 18, du venter på at se, om context pakken vil signalere, at 50 millisekunder er op. Uanset hvilket signal du modtager først, bliver det behandlet.

et vigtigt aspekt af denne algoritme er brugen af den bufrede kanal på 1. Hvis medarbejderen ikke er færdig i tide, går du videre uden at give medarbejderen nogen meddelelse. Fra medarbejderperspektivet sender de dig altid rapporten på linje 11, og de er blinde, hvis du er der eller ikke modtager den. Hvis du bruger en Unbuffered kanal, vil medarbejderen blokere for evigt forsøger at sende dig rapporten, hvis du går videre. Dette ville skabe en goroutine lækage. Så en bufret kanal på 1 bruges til at forhindre, at dette sker.

konklusion

attributterne til signalering omkring garantier, kanaltilstand og afsendelse er vigtige at kende og forstå, når du bruger kanaler (eller samtidighed). De hjælper dig med at implementere den bedste opførsel, du har brug for til de samtidige programmer og algoritmer, du skriver. De vil hjælpe dig med at finde fejl og snuse ud potentielt dårlig kode.

i dette indlæg har jeg delt et par eksempler på programmer, der viser, hvordan attributterne til signalering fungerer i forskellige scenarier. Der er undtagelser fra enhver regel, men disse mønstre er et godt fundament at starte.

gennemgå disse konturer som en oversigt over hvornår og hvordan man effektivt tænker på og bruger kanaler:

Sprogmekanik

  • brug kanaler til at orkestrere og koordinere goroutiner.
    • fokus på signalattributterne og ikke deling af data.
    • signalering med data eller uden data.
    • spørgsmålstegn ved deres anvendelse til synkronisering af adgang til delt tilstand.
      • der er tilfælde, hvor kanaler kan være enklere for dette, men oprindeligt spørgsmål.
  • unbuffered kanaler:
    • Modtag sker før sendingen.
    • fordel: 100% garanti signalet er modtaget.
    • omkostninger: Ukendt latenstid på, hvornår signalet vil blive modtaget.
  • bufferede kanaler:
    • Send sker før modtagelsen.
    • fordel: reducer blokerende latenstid mellem signalering.
    • omkostninger: ingen garanti, når signalet er modtaget.
      • jo større buffer, jo mindre garanti.
      • Buffer på 1 kan give dig en Forsinket afsendelse af garanti.
  • Lukningskanaler:
    • Luk sker før modtagelsen (som bufferet).
    • signalering uden data.
    • perfekt til signalering af aflysninger og deadlines.
  • nul kanaler:
    • Send og modtag blok.
    • sluk signalering
    • perfekt til hastighedsbegrænsende eller kortvarige stop.

designfilosofi

  • hvis en given sending på en kanal kan få den afsendende goroutine til at blokere:
    • ikke tilladt at bruge en bufret kanal større end 1.
      • buffere større end 1 skal have grund/målinger.
    • skal vide, hvad der sker, når den afsendende goroutine blokerer.
  • hvis en given sending på en kanal ikke får den afsendende goroutine til at blokere:
    • du har det nøjagtige antal buffere for hver sending.
      • Fan ud mønster
    • du har bufferen målt for maksimal kapacitet.
      • Drop mønster
  • mindre er mere med buffere.
    • tænk ikke på ydeevne, når du tænker på buffere.
    • buffere kan bidrage til at reducere blokerende latenstid mellem signalering.
      • at reducere blokerende latenstid mod nul betyder ikke nødvendigvis bedre gennemstrømning.
      • hvis en buffer på en giver dig god nok gennemstrømning, så hold den.
      • Spørgsmålsbuffere, der er større end en og måler for størrelse.
      • Find den mindste mulige buffer, der giver god nok gennemstrømning.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.