Kazi ya Kazi ya Kazi ya Kazi Jumla ya sifa za ishara za Go ni msaada wa ndani kwa concurrency. Goroutines na njia ni primitives rahisi na ufanisi kwa maandishi ya mipango ya pamoja. Lakini, kujaribu mipango ya pamoja inaweza kuwa ngumu na inaweza kuwa na makosa. Katika Go 1.24, tunatoa kipimo kipya cha majaribio cha ili kusaidia kujaribu msimbo wa pamoja. testing/synctest Utafutaji / Synctest Katika Go 1.24, mfuko wa ni wa majaribio na hauhusiani na ahadi ya ushirikiano wa Go. Haijulikani kwa kiwango cha chini. Ili kuitumia, unapaswa kuunda msimbo wako kwa kutumia iliyowekwa katika mazingira yako. testing/synctest GOEXPERIMENT=synctest Utafutaji / Synctest Utafiti wa Utafiti wa Utafiti wa Utafiti wa Utafiti Utafiti wa programu za pamoja ni vigumu Kwa mwanzo, hebu tuangalie mfano rahisi. Function ya inapanga kazi ya kuitwa katika goroutine yake mwenyewe baada ya mazingira yamefutwa. Hapa ni mtihani wa uwezekano wa : context.AfterFunc AfterFunc Kifungu cha Mwisho Mimi ni mwanachama wa func TestAfterFunc(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) calledCh := make(chan struct{}) // kufungwa wakati AfterFunc inachukuliwa context.AfterFunc(ctx, func() { close(calledCh) }) // TODO: Tuhakikisha kwamba AfterFunc haijulikani. cancel() // TODO: Tuhakikisha kwamba AfterFunc imeitwa. } func TestAfterFunc(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) calledCh := make(chan struct{}) // kufungwa wakati AfterFunc imeitwa context.AfterFunc(ctx, func() { close(calledCh) }) // TODO: Tumaini kwamba AfterFunc haikuitwa. cancel() // TODO: Tumaini kwamba AfterFunc imeitwa. } Tunataka kuthibitisha hali mbili katika mtihani huu: kazi haijulikani kabla ya mtazamo kufutwa, na kazi imeitwa baada ya mtazamo kufutwa. ni Tunaweza kujaribu kwa urahisi kwamba kazi haikujulikana kama , lakini jinsi ya kuthibitisha kwamba ? Kwa maana ya kuwa yet haikujulikana kama Mtihani huu pia ni mbaya: milliseconds 10 ni muda mrefu kwenye kompyuta ya haraka, lakini sio kawaida kuona mapumziko ya sekunde kadhaa kwenye mifumo iliyoshirikiana na ya kujazwa . Kuanza kwa kutumia Msimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini? Kuanza kwa kutumia kwa ajili yaMsimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini? siwezi kufanya hivyo Mfano wa kawaida ni kusubiri kwa muda fulani kabla ya kuhitimisha kwamba tukio litakuwa si kutokea. // funcCalled inaelezea kama kazi ilichukuliwa. funcCalled := func() bool { select { case <-calledCh: return true case <-time.After(10 * time.Millisecond): return false } } kama funcCalled() { t.Fatalf("AfterFunc function called before context is canceled") } cancel() kama!funcCalled() { t.Fatalf("AfterFunc function is not called after context is canceled") } // funcCalled inaelezea kama kazi ilichukuliwa. funcCalled := func() bool { select { case <-calledCh: return true case <-time.After(10 * time.Millisecond): return false } } kama funcCalled() { t.Fatalf("AfterFunc kazi ilichukuliwa kabla ya mazingira ni kufutwa") } cancel() kama!funcCalled() { t.Fatalf("AfterFunc kazi haijulikana baada ya mazingira ni kufutwa") } Majaribio haya ni polepole: milliseconds 10 sio muda mwingi, lakini inajumuisha zaidi ya majaribio mengi. CI WANA Tunaweza kufanya mtihani kidogo kwa gharama ya kuifanya kuwa ngumu, na tunaweza kufanya yake kidogo kwa gharama ya kuifanya kuwa ngumu, lakini hatuwezi kufanya haraka na ya kuaminika. Ufuatiliaji wa mfuko wa mtihani / synctest Pakiti ya inakuwezesha kuandika upya mtihani huu kuwa rahisi, haraka, na ya kuaminika, bila mabadiliko yoyote katika mtihani wa mtihani. testing/synctest Utafutaji / Synctest Pakiti hii ina kazi mbili tu: na . Kwenda Wasubiri huita kazi katika goroutine mpya. goroutine hii na goroutine yoyote iliyoanzishwa na hiyo inapatikana katika mazingira ya kujitenga ambayo tunajulikana kama . inatarajia kila goroutine katika mpangilio wa goroutine ya sasa kuzuia goroutine nyingine katika mpangilio. Run bubble Wait Bubble Tutaandika tena mtihani wetu hapo juu kwa kutumia mfuko wa . testing/synctest Utafutaji / Synctest func TestAfterFunc(t *testing.T) { synctest.Run(func() { ctx, cancel := context.WithCancel(context.Background()) funcCalled := false context.AfterFunc(ctx, func() { funcCalled = true }) synctest.Wait() kama funcCalled { t.Fatalf("AfterFunc function called before context is canceled") } cancel() synctest.Wait() kama!funcCalled { t.Fatalf("AfterFunc function is not called after context is canceled") }) } func TestAfterFunc(t *testing.T) { synctest.Run(func() { ctx, cancel := context.WithCancel(context.Background()) funcCalled := false context.AfterFunc(ctx, func() { funcCalled = true }) synctest.Wait() kama funcCalled { t.Fatalf("AfterFunc function called before context is canceled") } cancel() synctest.Wait() kama!funcCalled { t.Fatalf("AfterFunc function is not called after context is canceled") } } Kuanzishwa kwa Msimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini Mifano ya Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha Kifungu cha 1.Kazi ya Kazi ya Kazi ya Kazi Hii ni karibu sawa na mtihani wetu wa awali, lakini tumefunika mtihani katika simu ya na tunaita kabla ya kudai kwamba kazi imeitwa au sio. synctest.Run synctest.Wait Synctest.Run Function ya inatarajia kila goroutine katika mpangilio wa wito wa kuzuia.Msimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini? Wait Utafiti huu sasa ni wa haraka na wa kuaminika. Majaribio pia ni rahisi: tumebadilisha channel ya na boolean. Kabla ya hapo tulihitaji kutumia channel ili kuepuka ushindani wa data kati ya goroutine ya mtihani na goroutine ya , lakini kazi ya sasa hutoa usindikaji huo. calledCh AfterFunc Wait Msimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini? Msimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini?Kazi ya Kazi ya Kazi ya Kazi ya KaziMsimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini? Kazi ya Kazi ya Kazi ya Kazi ya Kazi Kuanzishwa kwa Kuanzishwa kwa Detector ya mashindano anajua wito wa , na mtihani huu unatolewa wakati unaendesha na . Ikiwa tunapoteza wito wa pili wa , detector ya mashindano itatoa taarifa sahihi ya mashindano ya data katika mtihani. Wait -race Wait Utafiti wa wakati Msimbo wa ushindani mara nyingi unashughulikia wakati. Utafiti wa msimbo unaofanya kazi na muda inaweza kuwa vigumu. Matumizi ya wakati halisi katika majaribio hufanya majaribio ya polepole na mabaya, kama tulivyoona hapo juu. Matumizi ya wakati wa uongo inahitaji kuepuka kazi za mfuko wa , na kubuni msimbo unaofanya majaribio ili kufanya kazi na muda wa uongo wa chaguo. time Pakiti ya inafanya kuwa rahisi kujaribu msimbo unaotumia muda. testing/synctest Utafutaji / Synctest Goroutines katika mpangilio ulianza na kutumia wakati wa uongo. Kwenye mpangilio, kazi katika mfuko wa hufanya kazi kwenye wakati wa uongo.Kuanza kwa kutumia Kazi ya Kazi ya Kazi ya Kazi ya Kazi Run time Kwa kuonyesha, hebu tuandikishe mtihani kwa kazi. huunda mtoto wa mazingira, ambayo huishia baada ya muda uliopangwa. context.WithTimeout WithTimeout context.WithTimeout WithTimeoutKuanzisha mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juuKuanzisha mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu Kuanzishwa kwa Msimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini Msimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini? Kuanza kwa kutumia Kuanza kwa kutumia Mara nyingi majaribio ya mteja na seva ya mawasiliano yanaweza kutumia uhusiano wa mtandao wa loopback. Wakati wa kufanya kazi na , hata hivyo, kwa kawaida tunataka kutumia uhusiano wa mtandao wa uongo ili kuruhusu kutambua wakati goroutines zote zimefungwa kwenye mtandao. Tutaanza mtihani huu kwa kuunda (mteja wa HTTP) ambayo hutumia uhusiano wa mtandao uliotengenezwa na . Tunaandika mtihani huu kama tulivyofanya kazi kwa wakati halisi. tofauti pekee ni kwamba tunashughulikia kazi ya mtihani katika , na kuita baada ya kila mtihani wa kusubiri wakati wa mfuko wa mazingira kuishia. synctest.Run synctest.Wait time.Sleep Synctest.Run mfano wa wakati.Sleep Blocking na mpira Mfano muhimu katika ni mpira kuwa . Hii hutokea wakati kila goroutine katika mpira ni kufungwa, na inaweza tu kufungwa na goroutine mwingine katika mpira. testing/synctest kufungwa kwa muda mrefu Utafutaji / Synctest kuzuiliwa kwa muda mrefu Ikiwa mpira unafungwa kwa muda mrefu: Ikiwa kuna wito wa nje wa , unarejeshwa. Wait Kama sivyo, muda unakwenda hadi wakati ujao ambao unaweza kufuta goroutine, ikiwa kuna. Kama sivyo, mpira unashindwa na huwa na hofu. Run Ikiwa kuna wito wa nje wa , unarejeshwa. Wait Vinginevyo, muda unakwenda hadi wakati ujao ambao unaweza kufungua goroutine, ikiwa kuna. Vinginevyo, mpangilio unafungwa na panic. Kwenda Bubble si kuzuiliwa kwa muda mrefu kama goroutine yoyote ni kuzuiliwa lakini inaweza kukumbukwa na tukio fulani kutoka nje ya bubble. Orodha kamili ya vitendo ambavyo vinafungua goroutine kwa muda mrefu ni: a kutuma au kupokea kwenye channel nil a kutuma au kupokea imefungwa kwenye channel iliyoundwa ndani ya mpangilio huo a maelezo ya kuchagua ambapo kila kesi ni kudumu kuzuia time.Sleep sync.Cond.Wait sync.WaitGroup.Wait a kutuma au kupokea kwenye channel ya nil a kutuma au kupokea imefungwa kwenye channel iliyoundwa ndani ya mpira huo mstari uliochaguliwa ambapo kila kesi ni kudumu kuzuia mfano Msimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini? kwa ajili ya mfano.mfano mfano wa wakati.Sleep Sync.Cond.Wait mfano.Mfano.Mfano mfano.Mfano.mfano.mfano.mfano kwa ajili ya > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > Kwa mfano, kazi ya huunda wanandoa wa ambazo hutumia uhusiano wa mtandao katika kumbukumbu na zinaweza kutumika katika majaribio ya synctest. Mifumo ya Kijamii.Conn Mfano wa Mifano ya Mifano Utaratibu juu ya si kuzuia kwa muda mrefu. sync.Mutex Sync.Mutex Ni kawaida kwa majukumu ya kupata mutex ya kimataifa. Kwa mfano, majukumu kadhaa katika pakiti ya kutafakari hutumia cache ya kimataifa iliyohifadhiwa na mutex. Ikiwa goroutine katika sinctest bubble inashindwa wakati unapata mutex iliyohifadhiwa na goroutine nje ya bubble, haina kuzuiliwa kwa muda mrefu - inachukuliwa, lakini itafungwa na goroutine kutoka nje ya bubble yake. Kwa sababu mutexes kwa kawaida si kuhifadhi kwa muda mrefu, sisi tu kuzuia yao kutoka ya kuzingatia. testing / synctest Utafutaji / Synctest Mipango ya Mipango ya Mipango Mipango yaliyoundwa ndani ya mpangilio hufanya tofauti na yale yaliyoundwa nje. Mafunzo ya channel ni kuzuia kwa muda mrefu tu ikiwa channel ni bubbled (kuumbwa katika bubble). sheria hizi zinahakikisha kwamba goroutine ni kuzuiliwa kwa muda mrefu tu wakati wa kuwasiliana na goroutines ndani ya mpangilio wake. Utaratibu wa nje wa I/O, kama vile kusoma kutoka kwa uhusiano wa mtandao, hauwezi kuzuia kwa muda mrefu. Ujumbe wa mtandao unaweza kufutwa na maandishi kutoka nje ya figo, labda hata kutoka kwa mchakato mwingine. Hata kama mwandishi pekee wa uhusiano wa mtandao pia ni katika figo moja, muda wa kuendesha hauwezi kutambua kati ya uhusiano unao kusubiri data zaidi kuja na moja ambapo kernel imepokea data na ni katika mchakato wa kuwasilisha. net.Pipe net.Conn pipe ya mtandao Uhai wa Bubble Function ya huanza goroutine katika mpangilio mpya. Inarudi wakati kila goroutine katika mpangilio umeondoka. Inasababisha hofu ikiwa mpangilio unafungwa kwa muda mrefu na haiwezi kufungwa kwa kuendeleza muda. Run Uhitaji kwamba kila goroutine katika kuondoka bubble kabla ya Run kurudi inamaanisha kwamba majaribio lazima kuwa makini kusafisha goroutine yoyote ya nyuma kabla ya kukamilisha. Utafiti wa msimbo wa mtandao Tazama mfano mwingine, wakati huu kutumia mfuko wa kujaribu mpango wa mtandao. Mfumo wa HTTP / HTTP / HTTP / HTTP testing/synctest Utafutaji / Synctest Mteja wa HTTP anayeuliza ombi anaweza kuwa na kichwa cha "Tazama: 100-kuendelea" ili kumwambia seva kwamba mteja ana data ya ziada ya kutuma.Mteja anaweza kisha kujibu na jibu la habari ya kuendelea 100 ili kumwomba ombi jingine, au na hali nyingine ili kumwambia mteja kwamba maudhui hayahitajika. Kwa mfano, mteja anayetumia faili kubwa anaweza kutumia kipengele hiki ili kuthibitisha kwamba server ana nia ya kukubali faili kabla ya kutuma. Test yetu itathibitisha kuwa wakati wa kutuma kichwa cha "Tazama: 100-kuendelea" mteja wa HTTP haitawasilisha maudhui ya ombi kabla ya seva inahitaji, na kwamba inatuma maudhui baada ya kupokea jibu la kuendelea 100. testing/synctest http.Transport net.Pipe Utafutaji / Synctest HTTP.Hifadhi ya Usalama pipe ya mtandao func Test(t *testing.T) { synctest.Run(func() { srvConn, cliConn := net.Pipe() defer srvConn.Close() defer cliConn.Close() tr := &http.Transport{ DialContext: func(ctx context.Context, mtandao, mstari wa anwani) (net.Conn, makosa) { return cliConn, nil }, // kuweka timeout isiyo ya null inawezesha "Expect: 100-continue" usindikaji. // Kwa sababu mtihani ufuatao hauwezi kusimama, // hatuwezi kukutana na timeout hii, // hata kama mtihani unachukua muda mrefu kuendesha kwenye mashine ya polepole. Msimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni niniMsimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini? Kuanzishwa kwa Kazi ya Utafiti kwa hrs Msimamizi Mjerumani akamwauliza kijana mwenyeji je jina la mahali ni nini func Test(t *testing.T) { synctest.Run(func() { srvConn, cliConn := net.Pipe() defer srvConn.Close() defer cliConn.Close() tr := &http.Transport{ DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { return cliConn, nil }, // Seting a non-zero timeout enables "Expect: 100-continue" handling. // Kwa kuwa mtihani ufuatao hauwezi kulala, // hatuwezi kukutana na hii timeout, // hata kama mtihani unachukua muda mrefu kuendesha kwenye mashine ya polepole. Mifumo ya Mifumo ya Strings.Builder Sisi kutuma ombi juu ya usafirishaji huu na mkusanyiko wa kichwa "Hata: 100 kuendelea." ombi inatumwa katika goroutine mpya, kwa sababu haitakuwa kamili mpaka mwisho wa mtihani. mwili := "kuomba mwili" go func() { req, _ := http.NewRequest("PUT", "http://test.tld/", strings.NewReader(body)) req.Header.Set("Uhitaji", "100-kuendelea") resp, err := tr.RoundTrip(req) kama err!= nil { t.Errorf("RoundTrip: makosa isiyotarajiwa %v", err) } else resp {.Body.Close() }() mwili := "kuomba mwili" go func() { req, _ := http.NewRequest("PUT", "http://test.tld/", strings.NewReader(body)) req.Header.Set("Uhitaji", "100-kuendelea") resp, err := tr.RoundTrip(req) kama err!= nil { t.Errorf("RoundTrip: makosa ya kutokuwa na matarajio %v", err) } mwingine { resp.Body.Close() } }() Tunaweza kusoma vichwa vya maombi vilivyotumwa na mteja. req, err := http.ReadRequest(bufio.NewReader(srvConn)) kama err!= nil { t.Fatalf("ReadRequest: %v", err) } req, err := http.ReadRequest(bufio.NewReader(srvConn)) kama err!= nil { t.Fatalf("ReadRequest: %v", err) } Sasa tunakuja kwenye moyo wa mtihani.Tunataka kuthibitisha kwamba mteja hatutuma mwili wa ombi bado. Tutaanza goroutine mpya kwa kurekodi mwili uliotumwa kwa seva katika , kusubiri goroutine zote katika mpangilio wa kuzuia, na kuthibitisha kwamba hatuna kusoma chochote kutoka kwa mwili bado. strings.Builder Ikiwa tunasahau wito wa , detector ya mashindano itatoa malalamiko sahihi kuhusu mashindano ya data, lakini kwa hii ni salama. synctest.Wait Wait var gotBody strings.Builder go io.Copy(&gotBody, req.Body) synctest.Wait() kama got := gotBody.String(); got!= "" { t.Fatalf("kabla ya kutuma 100 kuendelea, kusoma mwili: %q", got) } var gotBody strings.Builder go io.Copy(&gotBody, req.Body) synctest.Wait() kama got := gotBody.String(); got!= "" { t.Fatalf("kabla ya kutuma 100 kuendelea, kusoma mwili: %q", got) } Tunaandika jibu la "100 kuendelea" kwa mteja na kuthibitisha kwamba sasa inatuma mwili wa ombi. srvConn.Write([]byte("HTTP/1.1 100 Continue\r\r\n\n")) synctest.Wait() kama got := gotBody.String(); got!= mwili { t.Fatalf(" baada ya kutuma 100 kuendelea, kusoma mwili %q, wanataka %q", got, mwili) } srvConn.Write([]byte("HTTP/1.1 100 Continue\r\n\n\n")) synctest.Wait() kama got := gotBody.String(); got!= mwili { t.Fatalf(" baada ya kutuma 100 kuendelea, kusoma mwili %q, wanataka %q", got, mwili) } Na hatimaye, sisi kumaliza kwa kutuma "200 OK" jibu ili kukamilisha ombi. Tumeanza goroutines kadhaa wakati wa mtihani huu. Wito wa utasubiri kwa wote wao kuondoka kabla ya kurudi. synctest.Run Synctest.Run srvConn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n") }) } msongamano.Weka([]byte("HTTP/1.1 200 OK\r\n\r\n") }) } Majaribio haya yanaweza kupanuliwa kwa urahisi ili kujaribu tabia zingine, kama vile kuthibitisha kwamba mwili wa ombi haukutumwa ikiwa seva haina kuuliza, au kwamba inatumwa ikiwa seva haina kujibu ndani ya muda. Hatua ya majaribio Tunaanzisha katika Go 1.24 kama mfuko wa majaribio. Kulingana na maoni na uzoefu tunaweza kuchapisha na au bila mabadiliko, kuendelea majaribio, au kuondoa katika toleo la baadaye la Go. testing/synctest Utafutaji / Synctest Paketi haiwezi kuonekana kwa default. kuitumia, fanyeni msimbo wako na iliyoundwa katika mazingira yako. GOEXPERIMENT=synctest Utafiti wa Utafiti wa Utafiti wa Utafiti wa Utafiti Tunataka kusikia maoni yako! Ikiwa unajaribu , tafadhali ripoti uzoefu wako, chanya au hasi, kwenye . testing/synctest go.dev/issue/67434 Utafutaji / Synctest go.dev/issue/67434 Mshahara: Mshahara ya kiroho Damien Neil Picha kutoka kwa juu ya Gabriel Gusmao Uplash Picha ya juu ya Gabriel Gusmao Unsplash Juz. Unsplash Makala hii inapatikana kwenye kwa leseni ya CC BY 4.0 DEED. Blog ya Go Makala hii inapatikana kwenye kwa leseni ya CC BY 4.0 DEED. Blog ya Go Baba wa Mtandao Baba wa Mtandao