Tack för att du prenumererar

introduktion

när jag började arbeta med GO: s kanaler för första gången gjorde jag misstaget att tänka på kanaler som en datastruktur. Jag såg kanaler som en kö som gav automatisk synkroniserad åtkomst mellan goroutines. Denna strukturella förståelse fick mig att skriva mycket dålig och komplicerad samtidig kod.

jag lärde mig med tiden att det är bäst att glömma hur kanaler är strukturerade och fokusera på hur de beter sig. Så nu när det gäller kanaler tänker jag på en sak: signalering. En kanal tillåter en goroutine att signalera en annan goroutine om en viss händelse. Signalering är kärnan i allt du bör göra med kanaler. Att tänka på kanaler som en signalmekanism gör att du kan skriva bättre kod med väldefinierat och mer exakt beteende.

för att förstå hur signalering fungerar måste vi förstå dess tre attribut:

  • garanti för leverans
  • State
  • med eller utan Data

dessa tre attribut arbetar tillsammans för att skapa en designfilosofi kring signalering. När jag diskuterar dessa attribut, jag kommer att ge ett antal kodexempel som visar signalering med dessa attribut tillämpas.

leveransgaranti

leveransgarantin baseras på en fråga: ”Behöver jag en garanti för att signalen som skickas av en viss goroutine har mottagits?”

med andra ord, med tanke på detta exempel i Lista 1:

Lista 1

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

behöver den sändande goroutine en garanti för att paper som skickas över kanalen på rad 05 mottogs av goroutine på rad 02 innan vi går vidare?

baserat på svaret på den här frågan kommer du att veta vilken av de två typerna av kanaler som ska användas: obuffrad eller buffrad. Varje kanal ger ett annat beteende kring leveransgarantier.

Figur 1: leveransgaranti

 leveransgaranti

garantier är viktiga, och om du inte tror det har jag massor av saker jag vill sälja dig. Naturligtvis försöker jag göra ett skämt, men blir du inte nervös när du inte har garantier i livet? Att ha en stark förståelse för huruvida du behöver en garanti är avgörande när du skriver samtidig programvara. När vi fortsätter lär du dig att bestämma.

tillstånd

beteendet hos en kanal påverkas direkt av dess nuvarande tillstånd. Tillståndet för en kanal kan vara noll, öppen eller stängd.

Lista 2 nedan visar hur man deklarerar eller placerar en kanal i var och en av dessa tre stater.

Lista 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 bestämmer hur sändnings-och mottagningsoperationerna beter sig.

signaler skickas och tas emot via en kanal. Säg inte läs / skriv eftersom kanaler inte utför I / O.

Figur 2 : tillstånd

tillstånd

när en kanal är i noll tillstånd, kommer alla sändnings-eller mottagningsförsök på kanalen att blockera. När en kanal är i öppet tillstånd kan signaler skickas och tas emot. När en kanal placeras i stängt tillstånd kan signaler inte längre skickas men det är fortfarande möjligt att ta emot signaler.

dessa tillstånd kommer att ge de olika beteenden du behöver för de olika situationer du stöter på. När du kombinerar tillstånd med leveransgaranti kan du börja analysera de kostnader/fördelar du får till följd av dina designval. I många fall kommer du också att kunna snabbt upptäcka buggar bara genom att läsa koden, eftersom du förstår hur kanalen kommer att bete sig.

med och utan Data

det sista signaleringsattributet som måste beaktas är om du behöver signalera med eller utan data.

du signalerar med data genom att utföra en sändning på en kanal.

Lista 3

01 ch <- "paper"

när du signalerar med data beror det vanligtvis på att:

  • en goroutine uppmanas att starta en ny uppgift.
  • en goroutine rapporterar tillbaka ett resultat.

du signalerar utan data genom att stänga en kanal.

lista 4

01 close(ch)

när du signalerar utan data beror det vanligtvis på att:

  • en goroutine blir tillsagd att stoppa vad de gör.
  • en goroutine rapporterar tillbaka de görs utan resultat.
  • en goroutine rapporterar att den har slutfört bearbetningen och stängts av.

det finns undantag från dessa regler, men det här är de stora användningsfallen och de vi kommer att fokusera på i det här inlägget. Jag skulle överväga undantag från dessa regler för att vara en initial kod lukt.

en fördel med signalering utan data är en enda goroutine kan signalera många goroutines på en gång. Signalering med data är alltid en 1 till 1 utbyte mellan goroutines.

signalering med Data

när du ska signalera med data finns det tre kanalkonfigurationsalternativ du kan välja beroende på vilken typ av garanti du behöver.

Figur 3 : Signalering med Data

de tre kanalalternativen är obuffrade, buffrade > 1 eller buffrade =1.

  • garanti

    • en obuffrad kanal ger dig en garanti för att en signal som skickas har mottagits.
      • eftersom mottagningen av signalen sker innan sändningen av signalen är klar.
  • ingen garanti

    • en buffrad kanal av storlek >1 ger dig ingen garanti för att en signal som skickas har mottagits.
      • eftersom sändningen av signalen sker innan mottagningen av signalen är klar.
  • försenad garanti

    • en buffrad kanal av Storlek =1 ger dig en försenad garanti. Det kan garantera att den tidigare signalen som skickades har mottagits.
      • eftersom mottagandet av den första signalen, händer innan sändningen av den andra signalen är klar.

buffertens storlek får aldrig vara ett slumptal, det måste alltid beräknas för någon väldefinierad begränsning. Det finns ingen oändlighet i datorer, allt måste ha någon väldefinierad begränsning oavsett om det är tid eller rum.

signalering utan Data

signalering utan data är huvudsakligen reserverad för avbokning. Det gör att en goroutine att signalera en annan goroutine att avbryta vad de gör och gå vidare. Avbokning kan genomföras med både obuffrade och buffrade kanaler, men med en buffrad kanal när inga data kommer att skickas är en kod lukt.

Figur 4 : Signalering utan Data

den inbyggda funktionen close används för att signalera utan data. Som förklarats ovan i avsnittet tillstånd kan du fortfarande ta emot signaler på en kanal som är stängd. Faktum är att alla mottagningar på en stängd kanal inte blockerar och mottagningsoperationen returnerar alltid.

i de flesta fall vill du använda standardbiblioteket context för att implementera signalering utan data. context-paketet använder en obuffrad kanal under för signaleringen och den inbyggda funktionen close för att signalera utan data.

om du väljer att använda din egen kanal för avbokning, snarare än kontextpaketet, bör din kanal vara av typen chan struct{}. Det är det nollutrymme, idiomatiska sättet att indikera en kanal som endast används för signalering.

scenarier

med dessa attribut på plats är det bästa sättet att ytterligare förstå hur de fungerar i praktiken att gå igenom en serie kodscenarier. Jag gillar att tänka på goroutines som människor när jag läser och skriver kanalbaserad kod. Denna visualisering hjälper verkligen, och jag kommer att använda den som ett hjälpmedel nedan.

Signal med data – garanti – obuffrade kanaler

när du behöver veta att en signal som skickas har tagits emot kommer två scenarier att spela in. Dessa väntar på uppgift och väntar på resultat.

Scenario 1-vänta på uppgift

Tänk på att vara chef och anställa en ny anställd. I det här scenariot vill du att din nya anställd ska utföra en uppgift men de måste vänta tills du är redo. Detta beror på att du måste lämna dem ett papper innan de börjar.

Lista 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å rad 02 i Lista 5 skapas en obuffrad kanal med attributet att string data kommer att skickas med signalen. Sedan på linje 04 anställs en anställd och får höra att vänta på din signal på linje 05 innan de gör sitt arbete. Linje 05 är kanalmottagningen, vilket får den anställde att blockera medan han väntar på det papper du skickar. När papperet är mottaget av arbetstagaren utför arbetstagaren arbetet och sedan är det klart och fritt att gå.

du som chef arbetar samtidigt med din nya medarbetare. Så när du har anställt arbetstagaren på rad 04 befinner du dig (på rad 12) Gör vad du behöver göra för att avblockera och signalera arbetstagaren. Observera, det var okänt hur lång tid det skulle ta att förbereda detta papper du behöver skicka.

så småningom är du redo att signalera den anställde. På linje 14 utför du en signal med data, data är det papper. Eftersom en obuffrad kanal används får du en garanti för att den anställde har fått papperet när din sändningsoperation är klar. Mottagandet sker före sändningen.

tekniskt sett är allt du vet att den anställde har papperet när din kanalsändningsoperation är klar. Efter båda kanaloperationerna kan Schemaläggaren välja att utföra vilket uttalande som helst. Nästa rad kod som körs antingen av dig eller den anställde är nondeterministic. Detta innebär att använda utskrifts uttalanden kan lura dig om tingens ordning.

Scenario 2-vänta på resultat

i det här nästa scenariot är saker omvända. Den här gången vill du att din nya medarbetare ska utföra en uppgift omedelbart när de anställs, och du måste vänta på resultatet av deras arbete. Du måste vänta eftersom du behöver papperet från dem innan du kan fortsätta.

lista 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å rad 02 i lista 6 skapas en obuffrad kanal med attributet att string data kommer att skickas med signalen. Sedan på rad 04 anställs en anställd och sätts omedelbart på jobbet. När du har anställt arbetstagaren på rad 04 befinner du dig nästa på rad 12 och väntar på pappersrapporten.

när arbetet har slutförts av arbetstagaren på rad 05 skickar de resultatet till dig på rad 07 genom att utföra en kanalsändning med data. Eftersom det här är en obuffrad kanal sker mottagandet före sändningen och arbetstagaren är garanterad att du har fått resultatet. När arbetstagaren har denna garanti är de färdiga och fria att gå. I det här scenariot har du ingen aning om hur lång tid det tar för arbetstagaren att slutföra uppgiften.

kostnad / nytta

en obuffrad kanal ger en garanti för att en signal som skickas mottogs. Det här är bra, men ingenting är gratis. Kostnaden för denna garanti är okänd latens. I scenariot vänta på uppgift har arbetstagaren ingen aning om hur lång tid det tar för dig att skicka det papperet. I väntan på Resultatscenario har du ingen aning om hur lång tid det kommer att ta den anställde att skicka det resultatet.

i båda scenarierna är denna okända latens något vi måste leva med eftersom garantin krävs. Logiken fungerar inte utan detta garanterade beteende.

Signal med Data – ingen garanti-buffrade kanaler >1

när du inte behöver veta att en signal som skickas har tagits emot spelar dessa två scenarier in: Fan Out and Drop.

en buffrad kanal har ett väldefinierat utrymme som kan användas för att lagra data som skickas. Så hur bestämmer du hur mycket utrymme du behöver? Svara på dessa frågor:

  • har jag en väldefinierad mängd arbete som ska slutföras?
    • hur mycket arbete finns det?
  • om min anställd inte kan fortsätta, kan jag kassera något nytt arbete?
    • hur mycket enastående arbete sätter mig på kapacitet?
  • vilken risknivå är jag villig att acceptera om mitt program avslutas oväntat?
    • allt som väntar i bufferten kommer att gå förlorat.

om dessa frågor inte är vettiga för det beteende du modellerar är det en kodlukt som använder en buffrad kanal som är större än 1 är förmodligen fel.

Scenario 1-fläkt ut

en fläkt ut mönster kan du kasta ett väl definierat antal anställda på ett problem som arbetar samtidigt. Eftersom du har en anställd för varje uppgift vet du exakt hur många rapporter du kommer att få. Du kan se till att det finns rätt mängd utrymme i din ruta för att få alla dessa rapporter. Detta har fördelen att dina anställda inte behöver vänta på att du skickar in sin rapport. De behöver dock var och en ta en tur att placera rapporten i rutan om de anländer till rutan vid eller nära samma tidpunkt.

Tänk dig att du är chef igen men den här gången anställer du ett team av anställda. Du har en individuell uppgift som du vill att varje anställd ska utföra. När varje enskild anställd avslutar sin uppgift måste de ge dig en pappersrapport som måste placeras i din låda på ditt skrivbord.

lista 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å rad 03 i lista 7 skapas en buffrad kanal med attributet att string data kommer att skickas med signalen. Den här gången skapas kanalen med 20 buffertar tack vare variabeln emps deklarerad på rad 02.

mellan raderna 05 till 10 anställs 20 anställda och de kommer omedelbart till jobbet. Du har ingen aning om hur lång tid varje anställd kommer att ta på linje 07. Sedan på rad 08 skickar de anställda pappersrapporten men den här gången blockerar sändningen inte att vänta på en mottagning. Eftersom det finns plats i rutan för varje anställd konkurrerar sändningen på kanalen bara med andra anställda som kanske vill skicka sin rapport vid eller nära samma tidpunkt.

koden mellan raderna 12 till 16 är allt du. Det är här du väntar på att alla 20 anställda ska avsluta sitt arbete och skicka sin rapport. På rad 12 är du i en slinga och på rad 13 blockeras du i en kanal som väntar på dina rapporter. När en rapport har mottagits skrivs rapporten ut på rad 14 och den lokala räknarvariabeln minskas för att indikera att en anställd är klar.

Scenario 2-släpp

ett droppmönster gör att du kan kasta bort arbete när dina anställda har kapacitet. Detta har fördelen av att fortsätta att acceptera arbete från dina kunder och aldrig tillämpa mottryck eller latens i godkännandet av det arbetet. Nyckeln här är att veta när du verkligen har kapacitet så att du inte under eller över förbinder dig till den mängd arbete du kommer att försöka få gjort. Vanligtvis är integrationstestning eller mätvärden vad du behöver för att hjälpa dig att identifiera detta nummer.

Tänk dig att du är chef igen och du anställer en enda anställd för att få jobbet gjort. Du har en individuell uppgift som du vill att medarbetaren ska utföra. När medarbetaren avslutar sin uppgift bryr du dig inte om att veta att de är klara. Allt som är viktigt är om du kan eller inte kan placera nytt arbete i lådan. Om du inte kan utföra sändningen vet du att din låda är full och den anställde har kapacitet. Vid denna tidpunkt måste det nya arbetet kasseras så att sakerna kan fortsätta röra sig.

lista 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å rad 03 i Lista 8 skapas en buffrad kanal med attributet att string data kommer att skickas med signalen. Den här gången skapas kanalen med 5 buffertar tack vare cap – konstanten deklarerad på rad 02.

mellan raderna 05 till 09 anställs en enskild anställd för att hantera arbetet. En for range används för kanalmottagningen. Varje gång ett papper tas emot bearbetas det på rad 07.

mellan raderna 11 till 19 försöker du skicka 20 pappersbitar till din anställd. Den här gången används en select – sats för att utföra sändningen inuti den första case på rad 14. Eftersom default – klausulen används inuti select på rad 16, om sändningen kommer att blockera eftersom det inte finns mer utrymme i bufferten, överges sändningen genom att köra rad 17.

slutligen på rad 21 anropas den inbyggda funktionen close mot kanalen. Detta kommer att signalera utan data till den anställde att de är klara och fria att gå när de har slutfört sitt tilldelade arbete..

kostnad / nytta

en buffrad kanal större än 1 ger ingen garanti för att en signal som skickas någonsin tas emot. Det finns en fördel med att gå bort från denna garanti, vilket är den reducerade eller ingen latens i kommunikationen mellan två goroutiner. I fan Out-scenariot finns det ett buffertutrymme för varje anställd som skickar en rapport. I Droppscenariot mäts bufferten för kapacitet och om kapaciteten uppnås tappas arbetet så att sakerna kan fortsätta röra sig.

i båda alternativen är denna brist på garanti något vi måste leva med eftersom minskningen av latens är viktigare. Kravet på noll till minsta latens utgör inte ett problem för systemets övergripande logik.

Signal med Datafördröjd garanti – buffrad Kanal 1

när det är nödvändigt att veta om den tidigare signalen som skickades har tagits emot innan du skickar en ny signal, väntar scenariot på uppgifter spelar in.

Scenario 1-vänta på uppgifter

i det här scenariot har du en ny anställd men de kommer att göra mer än bara en uppgift. Du kommer att mata dem många uppgifter, en efter en. De måste dock avsluta varje enskild uppgift innan de kan starta en ny. Eftersom de bara kan arbeta med en uppgift i taget kan det finnas latensproblem mellan överlämnandet av arbetet. Om latensen kan minskas utan att förlora garantin för att arbetstagaren arbetar med nästa uppgift kan det hjälpa.

det är här en buffrad kanal på 1 har nytta. Om allt går i förväntad takt mellan dig och arbetstagaren, behöver ingen av er vänta på den andra. Varje gång du skickar ett papper är bufferten tom. Varje gång din anställd når mer arbete är bufferten full. Det är en perfekt symmetri av arbetsflödet.

det bästa är detta. Om du när som helst försöker skicka ett papper och du inte kan eftersom bufferten är full, vet du att din anställd har problem och du slutar. Det är här den försenade Garantin kommer in. När bufferten är tom och du utför sändningen har du garanti för att din anställd har tagit det sista arbetet du skickade. Om du utför sändningen och du inte kan, har du garantin att de inte har det.

lista 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å rad 02 i lista 9 skapas en buffrad kanal av Storlek 1 med attributet att string data kommer att skickas med signalen. Mellan linjerna 04 till 08 anställs en enda anställd för att hantera arbetet. En for range används för kanalmottagningen. Varje gång ett papper tas emot bearbetas det på rad 06.

mellan raderna 10 till 13 börjar du skicka dina uppgifter till arbetstagaren. Om din anställd kan springa så fort du kan skicka minskar latensen mellan er två. Men med varje skicka du utför framgångsrikt, du har en garanti för att det sista arbetet du lämnat in arbetas med.

slutligen på rad 15 anropas den inbyggda funktionen close mot kanalen. Detta kommer att signalera utan data till den anställde att de är klara och fria att gå. Det sista arbetet du skickade in kommer dock att tas emot (spolas) innan for range avslutas.

Signal utan Datakontext

i det här sista scenariot ser du hur du kan avbryta en löpande goroutine med ett Context – värde från paketet context. Allt detta fungerar genom att utnyttja en obuffrad kanal som är stängd för att utföra en signal utan data.

du är chef en sista gång och du anställer en enda anställd för att få jobbet gjort. Den här gången är du inte villig att vänta på någon okänd tid för den anställde att avsluta. Du har en diskret tidsfrist och om arbetstagaren inte slutar i tid är du inte villig att vänta.

lista 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å rad 02 i notering 10 deklareras ett varaktighetsvärde som representerar hur länge arbetstagaren måste slutföra uppgiften. Detta värde används på rad 04 för att skapa ett context.Context – värde med en timeout på 50 millisekunder. Funktionen WithTimeout från paketet context returnerar ett Context – värde och en avbokningsfunktion.

context – paketet skapar en goroutine som stänger den obuffrade kanalen som är associerad med Context – värdet när varaktigheten är uppfylld. Du är ansvarig för att anropa funktionen cancel oavsett hur det går till. Detta kommer att rensa upp saker som har skapats för Context. Det är ok att funktionen cancel anropas mer än en gång.

på rad 05 uppskjuts funktionen cancel för att köras när denna funktion avslutas. På rad 07 skapas en buffrad kanal på 1, som kommer att användas av arbetstagaren för att skicka resultatet av sitt arbete. Sedan på linjerna 09 till 12 anställs arbetstagaren och omedelbart sätts på jobbet. Du har ingen aning om hur lång tid det kommer att ta den anställde att avsluta.

mellan raderna 14 till 20 använder du select – satsen för att ta emot på två kanaler. Motta på rad 15, du väntar på att arbetstagaren skickar ditt resultat. Mottagningen på rad 18, du väntar på att se om context – paketet kommer att signalera att 50 millisekunder är uppe. Oavsett vilken signal du får först kommer den att behandlas.

en viktig aspekt av denna algoritm är användningen av den buffrade kanalen 1. Om arbetstagaren inte slutar i tid går du vidare utan att ge arbetstagaren något meddelande. Ur medarbetarperspektivet kommer de alltid att skicka rapporten på rad 11 och de är blinda om du är där eller inte för att ta emot den. Om du använder en obuffrad kanal blockerar medarbetaren för alltid att försöka skicka rapporten om du går vidare. Detta skulle skapa en goroutine läcka. Så en buffrad kanal på 1 används för att förhindra att detta händer.

slutsats

attributen för signalering kring garantier, kanaltillstånd och sändning är viktiga att känna till och förstå när man använder kanaler (eller samtidighet). De hjälper dig att implementera det bästa beteendet du behöver för de samtidiga programmen och algoritmerna du skriver. De hjälper dig att hitta buggar och sniffa ut potentiellt dålig kod.

i det här inlägget har jag delat några exempelprogram som visar hur attributen för signalering fungerar i olika scenarier. Det finns undantag från varje regel men dessa mönster är en bra grund att börja.

granska dessa konturer som en sammanfattning av när och hur man effektivt tänker på och använder kanaler:

Språkmekanik

  • använd kanaler för att orkestrera och samordna goroutiner.
    • fokusera på signaleringsattributen och inte delning av data.
    • signalering med eller utan data.
    • fråga deras användning för att synkronisera åtkomst till delat tillstånd.
      • det finns fall där kanaler kan vara enklare för detta men initialt fråga.
  • obuffrade kanaler:
    • mottagning sker före sändningen.
    • fördel: 100% garanti signalen har mottagits.
    • kostnad: Okänd latens på när signalen kommer att tas emot.
  • buffrade kanaler:
    • skicka sker före mottagandet.
    • fördel: minska blockeringsfördröjningen mellan signalering.
    • kostnad: ingen garanti när signalen har mottagits.
      • ju större buffert, desto mindre garanti.
      • buffert på 1 kan ge dig en försenad sändning av garanti.
  • Stängningskanaler:
    • Stäng sker före mottagandet (som buffrat).
    • signalering utan data.
    • perfekt för signalering av avbokningar och tidsfrister.
  • noll kanaler:
    • skicka och ta emot block.
    • Stäng av signalering
    • perfekt för hastighetsbegränsande eller kortvariga stopp.

designfilosofi

  • om en viss sändning på en kanal kan orsaka att den sändande goroutinen blockerar:
    • får inte använda en buffrad kanal som är större än 1.
      • buffertar större än 1 måste ha anledning / mätningar.
    • måste veta vad som händer när den sändande goroutine block.
  • om en viss sändning på en kanal inte kommer att orsaka att den sändande goroutinen blockerar:
    • du har det exakta antalet buffertar för varje sändning.
      • fläkt ut mönster
    • du har bufferten mätt för max kapacitet.
      • släpp mönster
  • mindre är mer med buffertar.
    • tänk inte på prestanda när du tänker på buffertar.
    • buffertar kan bidra till att minska blockeringsfördröjningen mellan signalering.
      • att minska blockeringslatensen mot noll betyder inte nödvändigtvis bättre genomströmning.
      • om en buffert av en ger dig tillräckligt bra genomströmning, behåll den.
      • fråga buffertar som är större än en och mäter för storlek.
      • hitta den minsta möjliga bufferten som ger tillräckligt bra genomströmning.

Lämna ett svar

Din e-postadress kommer inte publiceras.