Dank u voor het abonneren

Inleiding

toen ik voor het eerst met GO ‘ s kanalen begon te werken, maakte ik de fout om over kanalen te denken als een gegevensstructuur. Ik zag kanalen als een wachtrij die automatisch gesynchroniseerde toegang bood tussen goroutines. Dit structurele begrip zorgde ervoor dat ik veel slechte en ingewikkelde gelijktijdige code schreef.

ik leerde in de loop van de tijd dat het het beste is om te vergeten hoe kanalen zijn gestructureerd en zich te concentreren op hoe ze zich gedragen. Als het op kanalen aankomt, denk ik aan één ding: signaleren. Een kanaal staat een goroutine toe om een andere goroutine te signaleren over een bepaalde gebeurtenis. Signalering is de kern van alles wat je moet doen met kanalen. Het denken van kanalen als een signaleringsmechanisme zal u toelaten om betere code te schrijven met goed gedefinieerd en nauwkeuriger gedrag.

om te begrijpen hoe signalering werkt, moeten we de drie attributen begrijpen:

  • garantie van levering
  • staat
  • met of zonder gegevens

deze drie kenmerken werken samen om een ontwerpfilosofie rond signalering te creëren. Nadat ik deze attributen heb besproken, zal ik een aantal codevoorbeelden geven die signalering met deze attributen demonstreren.

leveringsgarantie

leveringsgarantie is gebaseerd op één vraag: “heb ik een garantie nodig dat het door een bepaalde goroutine verzonden signaal is ontvangen?”

met andere woorden, gegeven dit voorbeeld in lijst 1:

1

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

heeft de verzendende goroutine een garantie nodig dat de paper die via het kanaal op lijn 05 wordt verzonden, door de goroutine op lijn 02 is ontvangen alvorens verder te gaan?

op basis van het antwoord op deze vraag, zult u weten welke van de twee soorten kanalen U moet gebruiken: Unbuffered of Buffered. Elk kanaal biedt een ander gedrag rond garanties van levering.

figuur 1: leveringsgarantie

 leveringsgarantie

garanties zijn belangrijk, en als u dat niet vindt, heb ik een heleboel dingen die ik u wil verkopen. Natuurlijk, Ik probeer een grap te maken, maar word je niet nerveus als je geen garanties hebt in het leven? Het hebben van een sterk begrip van het al dan niet u een garantie nodig heeft is cruciaal bij het schrijven van gelijktijdige software. Als we doorgaan, leer je hoe je moet beslissen.

Status

het gedrag van een kanaal wordt direct beïnvloed door de huidige toestand. De toestand van een kanaal kan nul, open of gesloten zijn.

onderstaande lijst 2 laat zien hoe een kanaal in elk van deze drie staten moet worden gedeclareerd of geplaatst.

Listing 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)

de status bepaalt hoe de verzend – en ontvangbewerkingen zich gedragen.

signalen worden verzonden en ontvangen via een kanaal. Zeg niet lezen / schrijven omdat kanalen Geen I / O.

Figuur 2: Status

Status

wanneer een kanaal in een nihil staat, zal elke poging tot verzenden of ontvangen op het kanaal blokkeren. Wanneer een kanaal in een open toestand is, kunnen signalen worden verzonden en ontvangen. Wanneer een kanaal in een gesloten toestand wordt geplaatst, kunnen signalen niet meer worden verzonden, maar is het nog steeds mogelijk om signalen te ontvangen.

deze toestanden bieden de verschillende gedragingen die u nodig hebt voor de verschillende situaties die u tegenkomt. Bij het combineren van staat met garantie van levering, kunt u beginnen met het analyseren van de kosten / baten die u maakt als gevolg van uw ontwerp keuzes. In veel gevallen zul je ook in staat zijn om snel bugs te herkennen door alleen maar de code te lezen, omdat je begrijpt hoe het kanaal zich gaat gedragen.

met en zonder gegevens

Het Laatste signaleringskenmerk waarmee rekening moet worden gehouden, is of u met of zonder gegevens moet signaleren.

u signeert met gegevens door een send uit te voeren op een kanaal.

Listing 3

01 ch <- "paper"

als je signaal geeft met data, is het meestal omdat:

  • een goroutine wordt gevraagd om een nieuwe taak te starten.
  • een goroutine rapporteert een resultaat.

u signeert zonder gegevens door een kanaal te sluiten.

Listing 4

01 close(ch)

als je signaal zonder gegevens, is het meestal omdat:

  • een goroutine wordt verteld om te stoppen met wat ze doen.
  • a goroutine meldt dat ze zonder resultaat zijn gedaan.
  • a goroutine meldt dat het de verwerking heeft voltooid en afgesloten.

er zijn uitzonderingen op deze regels, maar dit zijn de belangrijkste use cases en degene waar we ons in dit artikel op zullen richten. Ik zou uitzonderingen op deze regels beschouwen als een eerste code geur.

een voordeel van signalering zonder gegevens is dat een enkele goroutine meerdere goroutines tegelijk kan signaleren. Signalering met data is altijd een 1 op 1 uitwisseling tussen goroutines.

signaleren met Data

wanneer u gaat signaleren met data, zijn er drie kanaalconfiguratieopties die u kunt kiezen, afhankelijk van het type garantie dat u nodig hebt.

Figuur 3 : Signalering met gegevens

de drie kanaalopties zijn niet gebufferd, gebufferd >1 of Gebufferd = 1.

  • garantie

    • een niet-gebufferd kanaal geeft u de garantie dat een signaal ontvangen is.
      • omdat het ontvangen van het signaal plaatsvindt voordat het verzenden van het signaal voltooid is.
  • geen garantie

    • een gebufferd kanaal met een grootte >1 geeft u geen garantie dat een verzonden signaal is ontvangen.
      • omdat het verzenden van het signaal plaatsvindt voordat het ontvangen van het signaal voltooid is.
  • vertraagde garantie

    • een gebufferd kanaal met Grootte = 1 geeft u een vertraagde garantie. Het kan garanderen dat het vorige signaal dat werd verzonden is ontvangen.
      • omdat het ontvangen van het eerste signaal plaatsvindt voordat het verzenden van het tweede signaal voltooid is.

de grootte van de buffer mag nooit een willekeurig getal zijn, het moet altijd worden berekend voor een goed gedefinieerde beperking. Er is geen oneindigheid in computing, alles moet een bepaalde welomschreven beperking hebben of dat nu tijd of ruimte is.

signalering zonder gegevens

signalering zonder gegevens is hoofdzakelijk voorbehouden voor annulering. Het staat de ene goroutine toe om een andere goroutine te signaleren om te annuleren wat ze doen en verder te gaan. Annulering kan worden geïmplementeerd met behulp van zowel Unbuffered als Buffered kanalen, maar het gebruik van een gebufferd kanaal wanneer er geen gegevens worden verzonden is een code geur.

Figuur 4 : Signalering zonder gegevens

de ingebouwde functie close wordt gebruikt om zonder gegevens te signaleren. Zoals hierboven uitgelegd in de sectie staat, kunt u nog steeds signalen ontvangen op een kanaal dat gesloten is. In feite, elke ontvangen op een gesloten kanaal zal niet blokkeren en de ontvangst operatie keert altijd terug.

in de meeste gevallen wilt u het standaardbibliotheek context – pakket gebruiken om signalering zonder gegevens te implementeren. Het context pakket gebruikt een niet-gebufferd kanaal eronder voor de signalering en de ingebouwde functie close om zonder gegevens te signaleren.

als u ervoor kiest om uw eigen kanaal te gebruiken voor annulering, in plaats van het contextpakket, moet uw kanaal van het type chan struct{}zijn. Het is de nul-ruimte, idiomatische manier om een kanaal aan te geven dat alleen wordt gebruikt voor signalering.

scenario ‘s

met deze kenmerken is de beste manier om beter te begrijpen hoe ze in de praktijk werken door een reeks codescenario’ s te doorlopen. Ik vind het leuk om goroutines als mensen te zien als ik channel based code lees en schrijf. Deze visualisatie helpt echt, en Ik zal het gebruiken als een hulpmiddel hieronder.

signaal met Data – Guarantee – Unbuffered kanalen

wanneer u wilt weten dat een verzonden signaal is ontvangen, spelen twee scenario ‘ s een rol. Dit zijn wachten op Taak en wachten op resultaat.

Scenario 1-wachten op Taak

denk na over het zijn van een manager en het inhuren van een nieuwe werknemer. In dit scenario, U wilt dat uw nieuwe werknemer om een taak uit te voeren, maar ze moeten wachten tot u klaar bent. Dit komt omdat je ze een stuk papier moet geven voordat ze beginnen.

Listing 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 }

op Regel 02 in lijst 5 wordt een niet-gebufferd kanaal aangemaakt met het attribuut dat string gegevens met het signaal worden verzonden. Dan op lijn 04, Een werknemer wordt ingehuurd en verteld om te wachten op uw signaal op lijn 05 alvorens hun werk te doen. Lijn 05 is het kanaal ontvangen, waardoor de werknemer te blokkeren tijdens het wachten op het stuk papier dat u zal verzenden. Zodra het papier is ontvangen door de werknemer, de werknemer voert het werk en dan is gedaan en vrij om te gaan.

u werkt als manager samen met uw nieuwe werknemer. Dus nadat je de werknemer op lijn 04 hebt ingehuurd, merk je dat je (op lijn 12) doet wat je moet doen om de werknemer te deblokkeren en te signaleren. Let op, het was onbekend hoe lang het zou duren om dit stuk papier dat u moet verzenden voor te bereiden.

uiteindelijk bent u klaar om de werknemer te signaleren. Op lijn 14 voer je een signaal uit met data, de data is dat stuk papier. Aangezien er een niet gebufferd kanaal wordt gebruikt, krijgt u de garantie dat de werknemer het papier heeft ontvangen zodra uw verzend operatie is voltooid. De ontvangst gebeurt voor de verzending.

technisch gezien is het enige wat u weet dat de werknemer het papier heeft tegen de tijd dat uw kanaal verzend operatie is voltooid. Na beide kanaalbewerkingen kan de planner ervoor kiezen om elk statement uit te voeren dat hij wil. De volgende regel code die wordt uitgevoerd door u of de werknemer is niet-deterministisch. Dit betekent dat het gebruik van print statements je kan misleiden over de volgorde van de dingen.

Scenario 2-Wacht op resultaat

In dit volgende scenario worden de dingen omgekeerd. Deze keer wilt u dat uw nieuwe werknemer om een taak onmiddellijk uit te voeren wanneer ze worden ingehuurd, en je nodig hebt om te wachten op het resultaat van hun werk. Je moet wachten omdat je het papier van hen nodig hebt voordat je verder kunt.

Listing 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 }

op Regel 02 in lijst 6 wordt een niet-gebufferd kanaal aangemaakt met het attribuut dat string gegevens met het signaal worden verzonden. Vervolgens wordt op lijn 04 een medewerker aangenomen en onmiddellijk aan het werk gezet. Nadat je de werknemer op lijn 04 hebt aangenomen, ben je de volgende op lijn 12, wachtend op het papieren rapport.

zodra het werk is voltooid door de werknemer op lijn 05, sturen ze het resultaat naar u op lijn 07 door het uitvoeren van een kanaal verzenden met gegevens. Aangezien dit een niet-gebufferd kanaal is, gebeurt de ontvangst vóór de verzending en de medewerker is gegarandeerd dat u het resultaat hebt ontvangen. Zodra de werknemer deze garantie heeft, zijn ze klaar en vrij om te gaan. In dit scenario, Je hebt geen idee hoe lang het gaat om de werknemer te nemen om de taak te voltooien.

kosten / baten

een niet-gebufferd kanaal biedt de garantie dat een signaal is ontvangen. Dit is geweldig, maar niets is gratis. De kosten van deze garantie zijn onbekend latency. In het wacht op Taak scenario, de werknemer heeft geen idee hoe lang het gaat duren voor u om dat papier te sturen. In de wacht op resultaat scenario, Je hebt geen idee hoe lang het gaat om de werknemer te nemen om u dat resultaat te sturen.

in beide scenario ‘ s is deze Onbekende latentie iets waar we mee moeten leven omdat de garantie vereist is. De logica werkt niet zonder dit gegarandeerde gedrag.

signaal met gegevens – zonder garantie-gebufferde kanalen >1

wanneer u niet hoeft te weten dat een signaal wordt verzonden is ontvangen, deze twee scenario ‘ s komen in het spel: Fan Out en Drop.

een gebufferd kanaal heeft een goed gedefinieerde ruimte die gebruikt kan worden om de verzonden gegevens op te slaan. Hoe beslis je hoeveel ruimte je nodig hebt? Beantwoord deze vragen:

  • heb ik een duidelijk omschreven hoeveelheid werk te voltooien?
    • hoeveel werk is er?
  • als mijn medewerker het niet bij kan houden, kan ik dan nieuw werk weggooien?
    • hoeveel uitstekend werk brengt mij op capaciteit?
  • welk risiconiveau ben ik bereid te accepteren als mijn programma onverwacht eindigt?
    • alles wat in de buffer wacht zal verloren gaan.

als deze vragen geen zin hebben voor het gedrag dat je modelleert, is het een code geur dat het gebruik van een gebufferd kanaal groter dan 1 waarschijnlijk verkeerd is.

Scenario 1-ventilator Out

met een ventilator out-patroon kunt u een goed gedefinieerd aantal werknemers bij een probleem gooien die gelijktijdig werken. Aangezien u voor elke taak één medewerker hebt, weet u precies hoeveel rapporten u ontvangt. U kunt ervoor zorgen dat er de juiste hoeveelheid ruimte in uw doos om al die rapporten te ontvangen. Dit heeft als voordeel dat uw medewerkers niet hoeven te wachten tot u hun rapport indient. Ze moeten echter elk een beurt nemen om het rapport in uw doos te plaatsen als ze op of in de buurt van hetzelfde moment bij de doos aankomen.

stel je voor dat je weer de manager bent, maar deze keer neem je een team van werknemers in dienst. U hebt een individuele taak die u wilt dat elke werknemer uit te voeren. Als elke individuele werknemer klaar is met hun taak, ze nodig hebben om u te voorzien van een papieren rapport dat moet worden geplaatst in uw doos op uw bureau.

Listing 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 }

op Regel 03 in Lijst 7 wordt een gebufferd kanaal aangemaakt met het attribuut dat string gegevens met het signaal worden verzonden. Deze keer wordt het kanaal aangemaakt met 20 buffers dankzij de variabele emps die is gedeclareerd op lijn 02.

tussen de lijnen 05 tot en met 10 worden 20 werknemers aangenomen en gaan zij onmiddellijk aan het werk. Je hebt geen idee hoe lang elke werknemer gaat nemen op lijn 07. Dan op lijn 08, de werknemers sturen het papieren rapport, maar deze keer de send niet blokkeren wachten op een ontvangen. Aangezien er ruimte in de doos voor elke werknemer, de send op het kanaal is alleen concurreren met andere werknemers die kunnen willen hun rapport te verzenden op of in de buurt van hetzelfde moment.

de code tussen de regels 12 tot en met 16 is helemaal u. Hier wacht je op alle 20 werknemers om hun werk af te maken en hun rapport op te sturen. Op lijn 12, bent u in een lus en op lijn 13 bent u geblokkeerd in een kanaal ontvangen te wachten op uw rapporten. Zodra een rapport is ontvangen, wordt het rapport afgedrukt op lijn 14 en de lokale teller variabele wordt verlaagd om aan te geven dat een werknemer is gedaan.

Scenario 2-Drop

met een droppatroon kunt u werk weggooien wanneer uw werknemer(s) op capaciteit zit. Dit heeft het voordeel van het blijven accepteren van werk van uw klanten en nooit het toepassen van tegendruk of latency in de aanvaarding van dat werk. De sleutel hier is te weten wanneer je echt op capaciteit, zodat je niet onder of over commit aan de hoeveelheid werk die je zal proberen om gedaan te krijgen. Meestal integratie testen of metrics is wat je nodig hebt om u te helpen dit nummer te identificeren.

stel je voor dat je weer de manager bent en dat je één enkele werknemer in dienst neemt om het werk gedaan te krijgen. Je hebt een individuele taak die je wilt dat de werknemer uit te voeren. Als de werknemer klaar is met hun taak je niet schelen om te weten dat ze klaar zijn. Het enige dat belangrijk is, is of je wel of niet nieuw werk in de doos kunt plaatsen. Als u het verzenden niet kunt uitvoeren, dan weet u dat uw doos vol is en de werknemer op capaciteit is. Op dit punt moet het nieuwe werk worden weggegooid zodat de dingen in beweging kunnen blijven.

Listing 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 }

op Regel 03 in lijst 8 wordt een gebufferd kanaal aangemaakt met het attribuut dat string gegevens met het signaal worden verzonden. Deze keer wordt het kanaal aangemaakt met 5 buffers dankzij de constante cap die is gedeclareerd op lijn 02.

tussen de lijnen 05 tot en met 09 wordt één werknemer ingehuurd om het werk te verrichten. Een for range wordt gebruikt voor het ontvangen van het kanaal. Elke keer dat een stuk papier wordt ontvangen wordt het verwerkt op lijn 07.

tussen de regels 11 tot en met 19 probeert u 20 papiertjes naar uw medewerker te sturen. Deze keer wordt een select statement gebruikt om de verzending uit te voeren binnen de eerste case op regel 14. Aangezien de default – clausule wordt gebruikt binnen de select op Regel 16, wordt de send door het uitvoeren van regel 17 verlaten als de send wordt geblokkeerd omdat er geen ruimte meer is in de buffer.

op lijn 21 wordt de ingebouwde functie close aangeroepen tegen het kanaal. Dit zal signaleren zonder gegevens aan de werknemer ze zijn gedaan en vrij om te gaan zodra ze hun toegewezen werk voltooid..

kosten / baten

een gebufferd kanaal groter dan 1 biedt geen garantie dat een signaal dat wordt verzonden ooit wordt ontvangen. Er is een voordeel van het weglopen van deze garantie, die is de verminderde of geen latentie in de communicatie tussen twee goroutines. In het Fan Out scenario is er een bufferruimte voor elke werknemer die een rapport zal verzenden. In het Dropscenario wordt de buffer gemeten voor capaciteit en als de capaciteit wordt bereikt, wordt het werk gedropt zodat dingen in beweging kunnen blijven.

in beide opties is dit gebrek aan garantie iets waar we mee moeten leven, omdat de vermindering van de latentie belangrijker is. De eis van nul tot minimale latentie vormt geen probleem voor de algemene logica van het systeem.

signaal met Data – Delayed Guarantee – Buffered Channel 1

wanneer het nodig is om te weten of het vorige signaal dat werd verzonden is ontvangen voordat een nieuw signaal wordt verzonden, speelt het wacht op taken scenario een rol.

Scenario 1-wacht op taken

In dit scenario hebt u een nieuwe werknemer, maar zij zullen meer dan één taak uitvoeren. Je gaat ze vele taken geven, de een na de ander. Ze moeten echter elke individuele taak afmaken voordat ze een nieuwe kunnen starten. Aangezien zij slechts aan één taak tegelijk kunnen werken, kunnen er latentieproblemen zijn tussen de overdracht van het werk. Als de latency kan worden verminderd zonder verlies van de garantie dat de werknemer werkt aan de volgende taak, het zou kunnen helpen.

dit is waar een gebufferd kanaal van 1 voordeel heeft. Als alles draait op het verwachte tempo tussen u en de werknemer, geen van jullie hoeft te wachten op de andere. Elke keer als je een stuk papier stuurt, is de buffer leeg. Elke keer dat uw werknemer reikt voor meer werk, de buffer is vol. Het is een perfecte symmetrie van de werkstroom.

het beste deel is dit. Als je op enig moment probeert om een stuk papier te sturen en je kunt niet omdat de buffer vol is, weet je dat je werknemer een probleem heeft en je stopt. Dit is waar die vertraagde garantie komt in. Wanneer de buffer leeg is en u de verzending uitvoert, heeft u de garantie dat uw medewerker het laatste werk dat u hebt verzonden heeft meegenomen. Als je het verzenden uitvoert en je kunt het niet, heb je de garantie dat ze het niet hebben gedaan.

Listing 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 }

op Regel 02 in lijst 9 wordt een gebufferd kanaal van grootte 1 aangemaakt met het attribuut dat string gegevens met het signaal worden verzonden. Tussen de lijnen 04 tot en met 08 wordt een enkele werknemer ingehuurd om het werk te behandelen. Een for range wordt gebruikt voor het ontvangen van het kanaal. Elke keer dat een stuk papier wordt ontvangen wordt het verwerkt op lijn 06.

tussen de regels 10 tot en met 13 begint u uw taken naar de werknemer te sturen. Als uw werknemer zo snel kan lopen als u kunt verzenden, wordt de latency tussen jullie twee verminderd. Maar bij elke verzending die u succesvol uitvoert, hebt u de garantie dat het laatste stuk werk dat u hebt ingediend wordt gewerkt aan.

op lijn 15 wordt de ingebouwde functie close aangeroepen tegen het kanaal. Dit zal signaleren zonder gegevens aan de werknemer ze zijn gedaan en vrij om te gaan. Echter, het laatste stuk werk dat u heeft ingediend zal worden ontvangen (gespoeld) voordat de for range wordt beëindigd.

signaal zonder Data-Context

In dit laatste scenario zult u zien hoe u een draaiende goroutine kunt annuleren met een Context waarde uit het context pakket. Dit alles werkt door gebruik te maken van een niet-gebufferd kanaal dat is gesloten om een signaal uit te voeren zonder gegevens.

u bent de manager voor de laatste keer en u huurt een enkele werknemer in om het werk gedaan te krijgen. Deze keer bent u niet bereid om te wachten op een onbekende hoeveelheid tijd voor de werknemer te voltooien. Je hebt een discrete deadline en als de werknemer niet op tijd klaar is, ben je niet bereid om te wachten.

Listing 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 }

op Regel 02 in lijst 10 wordt een duurwaarde aangegeven die aangeeft hoe lang de werknemer de taak zal moeten voltooien. Deze waarde wordt gebruikt op Regel 04 om een context.Context waarde aan te maken met een time-out van 50 milliseconden. De WithTimeout functie van het context pakket geeft een Context waarde en een annuleringsfunctie terug.

het context – pakket maakt een goroutine aan die het niet-gebufferde kanaal dat geassocieerd is met de Context – waarde zal sluiten zodra aan de duur is voldaan. U bent verantwoordelijk voor het aanroepen van de functie cancel, ongeacht hoe de zaken verlopen. Dit zal dingen opschonen die gemaakt zijn voor de Context. Het is ok dat de cancel functie meerdere keren wordt aangeroepen.

op Regel 05 wordt de functie cancel uitgesteld om te worden uitgevoerd zodra deze functie wordt beëindigd. Op lijn 07 wordt een gebufferd kanaal van 1 aangemaakt, dat door de medewerker zal worden gebruikt om het resultaat van zijn werk naar u toe te sturen. Vervolgens wordt op de lijnen 09 tot en met 12 de werknemer ingehuurd en onmiddellijk aan het werk gezet. Je hebt geen idee hoe lang het duurt voor de werknemer klaar is.

tussen regels 14 tot en met 20 gebruikt u de verklaring select om op twee kanalen te ontvangen. Bij het ontvangen op lijn 15, wacht je tot de medewerker je het resultaat toestuurt. De receive op lijn 18, wacht je om te zien of het context pakket gaat signaleren dat de 50 milliseconden voorbij is. Het signaal dat u het eerst ontvangt, wordt verwerkt.

een belangrijk aspect van dit algoritme is het gebruik van het gebufferde kanaal van 1. Als de werknemer niet op tijd klaar is, ga je verder zonder de werknemer een kennisgeving. Vanuit het perspectief van de werknemer sturen ze je altijd het rapport op lijn 11 en ze zijn blind of je er bent of niet om het te ontvangen. Als u een niet-gebufferd kanaal gebruikt, zal de werknemer voor altijd proberen om u het rapport te sturen als u verder gaat. Dit zou een goroutine lek veroorzaken. Dus een gebufferd kanaal van 1 wordt gebruikt om dit te voorkomen.

conclusie

de attributen van signalering rond garanties, kanaalstatus en verzenden zijn belangrijk om te weten en te begrijpen bij gebruik van kanalen (of concurrency). Zij zullen u helpen bij het implementeren van het beste gedrag dat u nodig hebt voor de gelijktijdige programma ‘ s en algoritmen die u schrijft. Zij zullen u helpen bugs te vinden en snuffelen uit potentieel slechte code.

In dit bericht heb ik een paar voorbeeldprogramma ’s gedeeld die laten zien hoe de attributen van signalering in verschillende scenario’ s werken. Er zijn uitzonderingen op elke regel, maar deze patronen zijn een goede basis om te beginnen.

bekijk deze contouren als een samenvatting van wanneer en hoe effectief na te denken over en gebruik te maken van kanalen:

Taalmechanica

  • gebruiken kanalen om goroutines te orkestreren en te coördineren.
    • Focus op de signaalkenmerken en niet op het delen van gegevens.
    • signalering met of zonder gegevens.
    • vraag het gebruik ervan af voor het synchroniseren van toegang tot gedeelde status.
      • er zijn gevallen waarin kanalen hiervoor eenvoudiger kunnen zijn, maar in eerste instantie vragen.
  • niet-gebufferde kanalen:
    • ontvangen gebeurt vóór het verzenden.
    • voordeel: 100% garantie dat het signaal is ontvangen.
    • kosten: Onbekende latentie wanneer het signaal wordt ontvangen.
  • gebufferde kanalen:
    • verzenden gebeurt vóór de ontvangst.
    • voordeel: verminder blokkerende latentie tussen signalering.
    • kosten: geen garantie wanneer het signaal is ontvangen.
      • hoe groter de buffer, hoe minder garantie.
      • Buffer van 1 kan u een vertraagde verzending van garantie geven.
  • kanalen sluiten:
    • sluiten gebeurt vóór de ontvangst (zoals gebufferd).
    • signalering zonder gegevens.
    • Perfect voor het signaleren van annuleringen en deadlines.
  • nihil kanalen:
    • zend-en Ontvangblok.
    • Uitschakelsignaal
    • Perfect voor snelheidsbegrenzers of korte onderbrekingen.

ontwerpfilosofie

  • als een bepaalde verzending op een kanaal ertoe kan leiden dat de verzendende goroutine blokkeert:
    • mag geen gebufferd kanaal groter dan 1 gebruiken.
      • Buffers groter dan 1 moeten reden/metingen hebben.
    • moet weten wat er gebeurt als de zendende goroutine blokkeert.
  • als een gegeven Send op een kanaal de verzendende goroutine niet blokkeert:
    • dan heb je het exacte aantal buffers voor elke send.
      • Uitwaaierpatroon
    • je hebt de buffer gemeten voor maximale capaciteit.
      • Droppatroon
  • minder is meer met buffers.
    • denk niet aan prestaties bij het denken over buffers.
    • Buffers kunnen helpen om blokkerende latentie tussen signalering te verminderen.
      • het verminderen van de blokkerende latentie naar nul betekent niet noodzakelijk een betere doorvoer.
      • als een buffer van één je goed genoeg doorvoer geeft, bewaar deze dan.
      • Vraagbuffers die groter zijn dan één en meten voor grootte.
      • Zoek de kleinst mogelijke buffer die voldoende doorvoer biedt.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.