Děkuji za Přihlášení

Úvod

Když jsem začal pracovat s kanály poprvé, udělal jsem chybu, myslet na programy jako datové struktury. Viděl jsem kanály jako frontu, která zajišťovala automatický synchronizovaný přístup mezi goroutines. Toto strukturální porozumění způsobilo, že jsem napsal spoustu špatných a komplikovaných souběžných kódů.

časem jsem se dozvěděl, že je nejlepší zapomenout na to, jak jsou kanály strukturovány, a zaměřit se na to, jak se chovají. Takže teď, pokud jde o kanály, myslím na jednu věc: signalizaci. Kanál umožňuje jedné goroutine signalizovat další goroutine o konkrétní události. Signalizace je jádrem všeho, co byste měli dělat s kanály. Myšlení kanálů jako signalizačního mechanismu vám umožní psát lepší kód s dobře definovaným a přesnějším chováním.

pochopit, jak signalizace funguje, musíme pochopit její tři atributy:

  • Záruka Doručení
  • Státu
  • S nebo Bez Data

Tyto tři atributy společně pracovat na vytvoření filozofie designu kolem signalizace. Poté, co jsem diskutovat o těchto atributů, uvedu řadu příkladů kódu, které demonstrují signalizaci s těmito atributy použity.

Záruka Dodání

Záruka Dodání je založena na jednu otázku: „potřebuji záruku, že signál, který konkrétní goroutine byla přijata?“

jinými slovy, vzhledem k tomu, tento příklad je ve výpisu 1:

Výpis 1

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

Dělá odeslání goroutine potřebují záruku, že paper posílány přes kanál na lince 05 byl přijat goroutine na lince 02 před přechodem na?

na základě odpovědi na tuto otázku budete vědět, který ze dvou typů kanálů použít: bez vyrovnávací paměti nebo vyrovnávací paměti. Každý kanál poskytuje jiné chování kolem záruk doručení.

Obrázek 1 : Záruka Dodání

Záruka Dodání

Záruky jsou důležité, a pokud si nemyslíte, že tak, mám spoustu věcí, které chci prodat. Samozřejmě, snažím se dělat vtip, ale nejsi nervózní, když nemáš záruky v životě? Mít silné pochopení toho, zda potřebujete záruku, je zásadní při psaní souběžného softwaru. Jak budeme pokračovat, naučíte se, jak se rozhodnout.

stav

chování kanálu je přímo ovlivněno jeho aktuálním stavem. Stav kanálu může být nulový, otevřený nebo uzavřený.

Seznam 2 níže ukazuje, jak deklarovat nebo umístit kanál do každého z těchto tří států.

Výpis 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)

stát určuje, jak se chovají operace odesílání a přijímání.

signály jsou odesílány a přijímány kanálem. Neříkej číst/psát, protože programy nemají provádět I/O.

Obrázek 2 : Stav

Státu

Když kanál je v nil státu, jakékoli odesílat nebo přijímat pokus na channel bude blokovat. Když je kanál v otevřeném stavu, signály mohou být odesílány a přijímány. Když je kanál umístěn do uzavřeného stavu, signály již nemohou být odeslány, ale je stále možné přijímat signály.

tyto stavy poskytnou různá chování, která potřebujete pro různé situace, se kterými se setkáte. Když kombinujete stav se zárukou dodání, můžete začít analyzovat náklady/výhody, které vám vzniknou v důsledku vašich možností návrhu. V mnoha případech budete také moci rychle odhalit chyby pouhým přečtením kódu, protože chápete, jak se kanál bude chovat.

s daty a bez dat

posledním atributem signalizace, který je třeba vzít v úvahu, je to, zda potřebujete signalizovat s daty nebo bez nich.

signalizujete s daty provedením odesílání na kanálu.

Výpis 3

01 ch <- "paper"

Když signál s daty, je to obvykle proto,:

  • A goroutine je požádán, aby začít nový úkol.
  • goroutine hlásí výsledek.

signalizujete bez dat uzavřením kanálu.

Výpis 4

01 close(ch)

Když signál bez data, je to obvykle proto,:

  • A goroutine je řečeno, zastavit to, co dělají.
  • Goroutine hlásí zpět, že jsou provedeny bez výsledku.
  • Goroutine hlásí, že dokončil zpracování a vypnul.

existují výjimky z těchto pravidel, ale to jsou hlavní případy použití a ty, na které se v tomto příspěvku zaměříme. Výjimky z těchto pravidel bych považoval za prvotní kodex.

jednou z výhod signalizace bez dat je, že jeden goroutin může signalizovat mnoho goroutinů najednou. Signalizace s daty je vždy 1 až 1 výměna mezi goroutiny.

Signalizace S Daty,

Když se chystáte signál s daty, tam jsou tři nastavení kanálu možností, které můžete zvolit v závislosti na typu záruky, které potřebujete.

obrázek 3 : Signalizace s daty

Tři možnosti kanálů jsou bez vyrovnávací paměti, pufrované >1 nebo pufrované =1.

  • záruka

    • kanál bez vyrovnávací paměti vám poskytuje záruku, že byl odeslán signál.
      • protože příjem signálu probíhá před dokončením odeslání signálu.
  • Žádná Záruka,

    • Pufrovaném kanálu o velikosti >1 dá vám Žádnou Záruku, že signál byl odeslán, byl přijat.
      • protože k odeslání signálu dochází před dokončením příjmu signálu.
  • Zpoždění Záruka

    • Pufrovaném kanál size =1 vám dává Zpoždění Záruky. Může zaručit, že byl přijat předchozí signál, který byl odeslán.
      • protože příjem prvního signálu, se stane před odesláním druhého signálu dokončí.

velikost vyrovnávací paměti nikdy nesmí být náhodné číslo, musí být vždy vypočtena pro některé dobře definované omezení. Ve výpočtech není nekonečno, všechno musí mít nějaké dobře definované omezení, ať už je to čas nebo prostor.

signalizace bez dat

signalizace bez dat je vyhrazena hlavně pro zrušení. To umožňuje jeden goroutine signalizovat další goroutine zrušit to, co dělají a jít dál. Zrušení může být implementováno pomocí kanálů bez vyrovnávací paměti i Buffered, ale použití Buffered kanálu, když nebudou odeslána žádná data, je vůně kódu.

obrázek 4 : Signalizace bez dat

Vestavěná funkce close slouží k signalizaci bez dat. Jak je vysvětleno výše v sekci Stav, stále můžete přijímat signály na uzavřeném kanálu. Ve skutečnosti se žádný příjem na uzavřeném kanálu nebude blokovat a operace příjmu se vždy vrátí.

ve většině případů chcete použít standardní knihovnu context pro implementaci signalizace bez dat. Balíček context používá pro signalizaci kanál bez vyrovnávací paměti a vestavěnou funkci close pro signalizaci bez dat.

Pokud se rozhodnete použít svůj vlastní kanál pro zrušení, nikoli v rámci balíčku, váš kanál by měl být typu chan struct{}. Jedná se o nulový prostor, idiomatický způsob označení kanálu používaného pouze pro signalizaci.

Scénáře

S těmito atributy v místě, nejlepší způsob, aby dále pochopit, jak fungují v praxi je projít sérii kód scénáře. Rád přemýšlím o goroutines jako o lidech, když čtu a píšu kód založený na kanálu. Tato vizualizace opravdu pomáhá a já ji použiji jako pomoc níže.

Signal With data – Guarantee-Unbuffered Channels

když potřebujete vědět, že byl odeslán signál, přicházejí do hry dva scénáře. Ty čekají na úkol a čekají na výsledek.

Scénář 1 – počkejte na úkol

Přemýšlejte o tom, že jste manažerem a najmete nového zaměstnance. V tomto scénáři chcete, aby váš nový zaměstnanec provedl úkol, ale musí počkat, až budete připraveni. Je to proto, že jim musíte před začátkem předat kus papíru.

Výpis 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 }

Na lince 02 ve výpisu 5, bez vyrovnávací pameti kanál je vytvořen s atributem string údaje budou zaslány s signál. Pak na lince 04, zaměstnanec je najat a řekl, aby počkal na váš signál na lince 05 před provedením své práce. Řádek 05 je příjem kanálu, což způsobí, že zaměstnanec zablokuje při čekání na kus papíru, který odešlete. Jakmile zaměstnanec obdrží papír, zaměstnanec vykoná práci a poté je hotový a může jít.

vy jako manažer pracujete souběžně s vaším novým zaměstnancem. Takže poté, co najmete zaměstnance na lince 04, zjistíte, že (na lince 12) děláte to,co musíte udělat, abyste odblokovali a signalizovali zaměstnanci. Poznámka, nebylo známo, jak dlouho bude trvat příprava tohoto kusu papíru, který musíte poslat.

nakonec jste připraveni signalizovat zaměstnance. Na lince 14 provádíte signál s daty, přičemž data jsou tímto kusem papíru. Vzhledem k tomu, Unbuffered kanál je používán, dostanete záruku, že zaměstnanec obdržel papír po dokončení operace odeslání. Příjem se stane před odesláním.

technicky vše, co víte, je, že zaměstnanec má papír v době, kdy vaše operace odeslání kanálu dokončí. Po obou kanálových operacích se Plánovač může rozhodnout provést jakýkoli příkaz, který chce. Další řádek kódu, který provádíte vy nebo zaměstnanec, je nedeterministický. To znamená, že použití tiskových prohlášení vás může oklamat o pořadí věcí.

scénář 2-počkejte na výsledek

v tomto dalším scénáři jsou věci obráceny. Tentokrát chcete, aby váš nový zaměstnanec provedl úkol okamžitě, když je najat, a musíte počkat na výsledek své práce. Než budete moci pokračovat, musíte počkat, protože od nich potřebujete papír.

Výpis 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 }

Na lince 02 ve výpisu 6, bez vyrovnávací pameti kanál je vytvořen s atributem string údaje budou zaslány s signál. Poté na lince 04 je zaměstnanec najat a je okamžitě uveden do práce. Poté, co najmete zaměstnance na lince 04, ocitnete se další na lince 12 a čekáte na papírovou zprávu.

jakmile je práce dokončena zaměstnancem na lince 05, odešle vám výsledek na lince 07 provedením kanálu odeslat s daty. Protože se jedná o bez vyrovnávací pameti kanál, zobrazí se stane předtím, než odeslat a zaměstnanec je zaručeno, že jste obdrželi výsledek. Jakmile má zaměstnanec tuto záruku, jsou hotovi a mohou jít. V tomto scénáři nemáte tušení, jak dlouho bude zaměstnanci trvat, než úkol dokončí.

náklady / přínos

bezúplatný kanál poskytuje záruku, že byl vyslán signál. To je skvělé, ale nic není zadarmo. Náklady na tuto záruku nejsou známy. Ve scénáři čekání na úkol zaměstnanec netuší, jak dlouho bude trvat, než tento papír odešlete. Ve scénáři čekání na výsledek nemáte tušení, jak dlouho bude zaměstnanci trvat, než vám tento výsledek pošle.

v obou scénářích je tato neznámá latence něco, s čím musíme žít, protože je vyžadována záruka. Bez tohoto zaručeného chování logika nefunguje.

signál s daty-bez záruky-Buffered kanály >1

pokud nepotřebujete vědět, že byl odeslán signál, přicházejí do hry tyto dva scénáře: Fan Out and Drop.

vyrovnávací kanál má dobře definovaný prostor, který lze použít k ukládání odeslaných dat. Jak se tedy rozhodnete, kolik místa potřebujete? Odpovězte na tyto otázky:

  • mám dobře definované množství práce, které mají být dokončeny?
    • kolik práce existuje?
  • pokud můj zaměstnanec nemůže držet krok, mohu zahodit jakoukoli novou práci?
    • kolik vynikající práce mi dává kapacitu?
  • jakou míru rizika jsem ochoten přijmout, pokud můj program neočekávaně skončí?
    • vše, co čeká ve vyrovnávací paměti, bude ztraceno.

Pokud tyto otázky nemají smysl pro chování modelování, je to kód vůni, která pomocí Vyrovnávací paměti kanálu větší než 1, je pravděpodobně špatně.

Scénář 1-Fan Out

vzor fan out vám umožňuje hodit dobře definovaný počet zaměstnanců na problém, který pracuje souběžně. Protože máte pro každý úkol jednoho zaměstnance, přesně víte, kolik zpráv obdržíte. Můžete se ujistit, že v krabici je správné množství místa pro příjem všech těchto zpráv. To má výhodu, že vaši zaměstnanci nemusí čekat, až předložíte svou zprávu. Je však třeba, aby se každý otočil umístěním zprávy do vaší krabice, pokud dorazí do krabice ve stejnou dobu nebo v její blízkosti.

Představte si, že jste opět manažerem, ale tentokrát najmete tým zaměstnanců. Máte individuální úkol, který má každý zaměstnanec provést. Jak každý jednotlivý zaměstnanec dokončí svůj úkol, musí vám poskytnout papírovou zprávu, která musí být umístěna v krabici na stole.

Výpis 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 }

Na řádku 03 ve výpisu 7, Vyrovnávací kanál je vytvořen s atributem string údaje budou zaslány s signál. Tentokrát je kanál vytvořen s 20 buffery díky proměnné emps deklarované na řádku 02.

mezi řádky 05 až 10 je najato 20 zaměstnanců a okamžitě se dostanou do práce. Nemáte tušení, jak dlouho bude každý zaměstnanec trvat na lince 07. Poté na lince 08 zaměstnanci pošlou papírovou zprávu, ale tentokrát odeslání neblokuje čekání na příjem. Vzhledem k tomu, že v krabici je místo pro každého zaměstnance, odesílání na kanálu soutěží pouze s ostatními zaměstnanci, kteří mohou chtít poslat svou zprávu ve stejnou dobu nebo v její blízkosti.

kód mezi řádky 12 až 16 je vše, co. Zde čekáte, až všech 20 zaměstnanců dokončí svou práci a odešle zprávu. Na lince 12 jste ve smyčce a na lince 13 jste zablokováni v kanálu, který čeká na vaše zprávy. Jakmile je zpráva přijata, zpráva je vytištěna na řádku 14 a místní proměnná čítače je snížena, aby označila zaměstnance.

scénář 2-Drop

drop Vzor vám umožní zahodit práci, když jsou vaši zaměstnanci v kapacitě. To má výhodu, že nadále přijímá práci od svých klientů a nikdy použití zpětného tlaku nebo zpoždění v přijetí této práce. Klíčem je vědět, kdy jste skutečně v kapacitě, takže se nezavazujete pod nebo nad množstvím práce,kterou se pokusíte udělat. Obvykle je to, co potřebujete k identifikaci tohoto čísla, testování integrace nebo metriky.

Představte si, že jste opět manažerem a najmete jednoho zaměstnance, aby dokončil práci. Máte individuální úkol, který má zaměstnanec provést. Když zaměstnanec dokončí svůj úkol, nezajímá vás, že jsou hotovi. Jediné, co je důležité, je, zda můžete nebo nemůžete umístit novou práci do krabice. Pokud nemůžete odeslat, pak víte, že Vaše schránka je plná a zaměstnanec je v kapacitě. V tomto okamžiku je třeba novou práci zlikvidovat, aby se věci mohly neustále pohybovat.

Výpis 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 }

Na řádku 03 ve výpisu 8, Vyrovnávací kanál je vytvořen s atributem string údaje budou zaslány s signál. Tentokrát je kanál vytvořen s 5 buffery díky konstantě cap deklarované na řádku 02.

mezi řádky 05 až 09 je najat jeden zaměstnanec, aby tuto práci zvládl. Pro příjem kanálu se používá for range. Pokaždé, když je přijat kus papíru, je zpracován na řádku 07.

mezi řádky 11 až 19 se pokusíte poslat zaměstnanci 20 kusů papíru. Tentokrát se použije příkaz select k provedení odeslání uvnitř prvního case na řádku 14. Protože klauzule default se používá uvnitř select na řádku 16, pokud se odesílání zablokuje, protože ve vyrovnávací paměti není více místa, je odeslání opuštěno provedením řádku 17.

konečně na lince 21 je proti kanálu volána Vestavěná funkce close. To signalizuje bez dat zaměstnanci, že jsou hotovi a mohou jít, jakmile dokončí přidělenou práci..

náklady / přínosy

vyrovnávací kanál větší než 1 neposkytuje žádnou záruku, že odeslaný signál bude někdy přijat. Výhodou je odchod z této záruky, což je snížená nebo žádná latence v komunikaci mezi dvěma goroutiny. Ve scénáři Fan Out je pro každého zaměstnance, který bude odesílat zprávu, vyrovnávací prostor. Ve scénáři poklesu, vyrovnávací paměť se měří na kapacitu a pokud je dosaženo kapacity, práce se sníží, aby se věci mohly neustále pohybovat.

v obou možnostech je tento nedostatek záruky něco, s čím musíme žít, protože snížení latence je důležitější. Požadavek nulové až minimální latence nepředstavuje problém pro celkovou logiku systému.

Signál S Daty – Zpoždění Záruka – Vyrovnávací Kanál 1

Když je nutné vědět, pokud se předchozí signál, který byl odeslán, byl přijat před odesláním nový signál, Čekání na Úkoly scénáře přicházejí do hry.

Scénář 1-počkejte na úkoly

v tomto scénáři máte nového zaměstnance, ale budou dělat více než jen jeden úkol. Budete jim krmit mnoho úkolů, jeden po druhém. Musí však dokončit každý jednotlivý úkol, než mohou začít nový. Vzhledem k tomu, že mohou pracovat pouze na jednom úkolu najednou, mohou existovat problémy s latencí mezi předáním práce. Pokud by latence mohla být snížena bez ztráty záruky, že zaměstnanec pracuje na dalším úkolu, mohlo by to pomoci.

to je místo, kde vyrovnávací kanál 1 má výhodu. Pokud vše běží očekávaným tempem mezi vámi a zaměstnancem, ani jeden z vás nebude muset čekat na druhého. Pokaždé, když pošlete kus papíru, vyrovnávací paměť je prázdná. Pokaždé, když váš zaměstnanec dosáhne více práce, vyrovnávací paměť je plná. Je to dokonalá symetrie pracovního toku.

nejlepší část je to. Pokud se kdykoli pokusíte poslat kus papíru a nemůžete, protože vyrovnávací paměť je plná, víte, že váš zaměstnanec má problém a zastavíte se. Tady přichází ta opožděná záruka. Když je vyrovnávací paměť prázdná a provedete odeslání, máte záruku, že váš zaměstnanec vzal poslední část práce, kterou jste odeslali. Pokud budete provádět odesílání a nemůžete, máte záruku, že nemají.

Výpis 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 }

Na lince 02 ve výpisu 9, Vyrovnávací paměti kanálu velikosti 1 je vytvořen s atributem string údaje budou zaslány s signál. Mezi řádky 04 až 08 je najat jediný zaměstnanec, který práci zvládne. Pro příjem kanálu se používá for range. Pokaždé, když je přijat kus papíru, je zpracován na řádku 06.

mezi řádky 10 až 13 začnete posílat své úkoly zaměstnanci. Pokud váš zaměstnanec může běžet tak rychle, jak můžete poslat, latence mezi vámi dvěma se sníží. Ale s každým odesláním úspěšně provádíte, máte záruku, že se pracuje na posledním díle, které jste odeslali.

konečně na lince 15 je volána Vestavěná funkce close proti kanálu. To bude signalizovat bez dat zaměstnanci, že jsou hotovi a mohou jít. Poslední část práce, kterou jste odeslali, však bude přijata (propláchnuta) před ukončením for range.

signál bez datového kontextu

v tomto posledním scénáři uvidíte, jak můžete zrušit běžící goroutine pomocí hodnoty Context z balíčku context. To vše funguje tak, že využívá nefunkční kanál, který je uzavřen, aby provedl signál bez dat.

jste naposledy manažerem a najmete jednoho zaměstnance, aby dokončil práci. Tentokrát nejste ochotni čekat na nějakou neznámou dobu, než zaměstnanec dokončí. Jste v diskrétním termínu a pokud zaměstnanec nedokončí včas, nejste ochotni čekat.

Výpis 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 }

na řádku 02 v seznamu 10 je deklarována hodnota trvání, která představuje, jak dlouho bude muset zaměstnanec dokončit úkol. Tato hodnota se používá na řádku 04 k vytvoření hodnoty context.Context s časovým limitem 50 milisekund. Funkce WithTimeout z balíčku context vrací hodnotu Context a funkci zrušení.

context balíček vytváří goroutine, že se uzavře bez vyrovnávací pameti kanál spojený s Context hodnota jednou trvání je splněna. Jste zodpovědní za volání funkce cancel bez ohledu na to, jak se věci vyvinou. Tím se vyčistí věci, které byly vytvořeny pro Context. Je v pořádku, aby byla funkce cancel volána více než jednou.

na řádku 05 je funkce cancel odložena, aby byla provedena po ukončení této funkce. Na lince 07 je vytvořen vyrovnávací kanál 1, který zaměstnanec použije k odeslání výsledku své práce. Poté na linkách 09 až 12 je zaměstnanec najat a okamžitě uveden do práce. Nemáte tušení, jak dlouho to bude trvat zaměstnance dokončit.

mezi řádky 14 až 20 použijete příkaz select pro příjem na dvou kanálech. Příjem na lince 15, počkáte, až vám zaměstnanec pošle svůj výsledek. Příjem na lince 18, počkáte, zda balíček context signalizuje, že 50 milisekund je nahoru. Bez ohledu na signál, který obdržíte jako první, bude zpracován.

důležitým aspektem tohoto algoritmu je použití pufrovaného kanálu 1. Pokud zaměstnanec nedokončí včas, jdete dál, aniž byste zaměstnanci oznámili. Z pohledu zaměstnance vám zprávu vždy pošlou na lince 11 a jsou slepí, pokud tam jste nebo ji nepřijmete. Používáte-li kanál bez vyrovnávací paměti, zaměstnanec bude navždy blokovat pokus o odeslání zprávy, pokud budete pokračovat. To by vytvořilo únik goroutine. Takže se používá vyrovnávací kanál 1, aby se tomu zabránilo.

závěr

atributy signalizace kolem záruk, stavu kanálu a odesílání jsou důležité znát a pochopit při použití kanálů (nebo souběžnosti). Pomohou vám při implementaci nejlepšího chování, které potřebujete pro souběžné programy a algoritmy, které píšete. Pomohou vám najít chyby a vyčenichat potenciálně špatný kód.

v tomto příspěvku jsem sdílel několik ukázkových programů, které ukazují, jak atributy signalizace fungují v různých scénářích. Existují výjimky z každého pravidla, ale tyto vzory jsou dobrým základem pro začátek.

Přečtěte si tyto obrysy jako souhrn toho, kdy a jak efektivně přemýšlet a používat kanály:

Jazyková mechanika

  • používá kanály k orchestraci a koordinaci goroutines.
    • zaměřte se na atributy signalizace a ne na sdílení dat.
    • signalizace s daty nebo bez dat.
    • zpochybňuje jejich použití pro synchronizaci přístupu ke sdílenému stavu.
      • existují případy, kdy kanály mohou být jednodušší, ale zpočátku otázka.
  • Unbuffered kanály:
    • příjem se stane před odesláním.
    • výhoda: 100% záruka, že signál byl přijat.
    • náklady: Neznámá latence, kdy bude signál přijat.
  • Buffered kanály:
    • Odeslat se stane před přijetím.
    • výhoda: snižte latenci blokování mezi signalizací.
    • náklady: po přijetí signálu není zaručena žádná záruka.
      • čím větší vyrovnávací paměť, tím menší záruka.
      • vyrovnávací paměť 1 vám může poskytnout jedno zpožděné odeslání záruky.
  • Zavírání kanálů:
    • Zavřít se stane předtím, než Přijímat (jako Vyrovnávací paměti).
    • signalizace bez dat.
    • ideální pro signalizaci zrušení a termíny.
  • nulové kanály:
    • odesílat a přijímat blok.
    • vypněte signalizaci
    • ideální pro omezení rychlosti nebo krátkodobé zastavení.

Filozofie Designu

  • Pokud dané Poslat na kanál, MOHOU způsobit odesílání goroutine pro blokování:
    • Není povoleno používat Vyrovnávací paměti kanálu větší než 1.
      • nárazníky větší než 1 musí mít důvod / měření.
    • musí vědět, co se stane, když vysílající goroutine blokuje.
  • pokud některý daný Send na kanálu nezpůsobí odesílání goroutine blokovat:
    • máte přesný počet vyrovnávacích pamětí pro každé odeslání.
      • vzor ventilátoru
    • máte vyrovnávací paměť naměřenou pro maximální kapacitu.
      • Drop pattern
  • méně je více s nárazníky.
    • nemyslete na výkon, když přemýšlíte o náraznících.
    • vyrovnávací paměti mohou pomoci snížit latenci blokování mezi signalizací.
      • snížení latence blokování směrem k nule nemusí nutně znamenat lepší propustnost.
      • pokud vám vyrovnávací paměť poskytuje dostatečně dobrou propustnost, ponechte si ji.
      • vyrovnávací paměti otázek, které jsou větší než jedna a měří velikost.
      • Najděte nejmenší možnou vyrovnávací paměť, která poskytuje dostatečnou propustnost.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.