.NET: Mea hana no ka hana me ka multithreading a me ka asynchrony. Mahele 1

Ke hoʻopuka nei au i ka ʻatikala mua ma Habr, ʻo ka unuhi ʻana i hoʻopuka ʻia ma ka hui ʻatikala blog.

ʻO ka pono e hana i kekahi mea asynchronously, me ke kali ʻole i ka hopena ma ʻaneʻi a i kēia manawa, a i ʻole e hoʻokaʻawale i nā hana nui i waena o kekahi mau ʻāpana e hana ana ia mea, aia ma mua o ka hiki ʻana mai o nā kamepiula. Me ko lākou hiki ʻana mai, ua ʻike nui ʻia kēia pono. I kēia manawa, i ka makahiki 2019, ke kākau nei au i kēia ʻatikala ma kahi pona me kahi kaʻina hana Intel Core 8-core, kahi e holo like ai nā kaʻina hana ma mua o hoʻokahi haneli, a ʻoi aku ka nui o nā kaula. Ma kahi kokoke, aia kahi kelepona liʻiliʻi liʻiliʻi, i kūʻai ʻia i ʻelua mau makahiki i hala aku nei, aia kahi kaʻina hana 8-core ma luna o ka moku. Ua piha nā kumuwaiwai kumuhana i nā ʻatikala a me nā wikiō kahi e mahalo ai kā lākou mea kākau i nā poʻokela poʻokela o kēia makahiki e hōʻike ana i nā kaʻina hana 16-core. Hāʻawi ʻo MS Azure i kahi mīkini uila me ka 20 core processor a me 128 TB RAM no ka liʻiliʻi ma mua o $2/hola. ʻO ka mea pōʻino, ʻaʻole hiki ke unuhi i ka nui a hoʻopaʻa i kēia mana me ka hiki ʻole ke hoʻokele i ka pilina o nā kaula.

Kau'ōlelo

Kaʻina hana - ʻO ka mea OS, kaʻawale wahi kikoʻī, loaʻa nā pae.
Loko - he mea OS, ka liʻiliʻi liʻiliʻi o ka hoʻokō, ʻāpana o kahi kaʻina hana, kaʻana like ʻana o nā milo i ka hoʻomanaʻo a me nā kumuwaiwai ʻē aʻe i waena o lākou iho i loko o kahi kaʻina hana.
Kūkākūkā - Waiwai OS, ka hiki ke holo i kekahi mau kaʻina hana i ka manawa like
Nui-core - kahi waiwai o ka mea hana, ka hiki ke hoʻohana i kekahi mau cores no ka hana ʻikepili
Ka hoʻoheheʻe ʻana - he waiwai o ka lolouila, ka hiki ke hana like me kekahi mau mea hana ma ke kino
Heluhelu nui - kahi waiwai o kahi kaʻina hana, ka hiki ke puʻunaue i ka hoʻoili ʻikepili ma waena o nā loina.
Hoʻolikelike - hana i kekahi mau hana kino i ka manawa like
Asynchrony - ka hoʻokō ʻana i kahi hana me ke kali ʻole i ka pau ʻana o kēia kaʻina hana; hiki ke hana ʻia ka hopena o ka hoʻokō ma hope.

Metapora

ʻAʻole maikaʻi nā wehewehe a pau a pono kekahi e wehewehe hou aku, no laila e hoʻohui wau i kahi ʻōlelo hoʻohālikelike e pili ana i ka kuke ʻana i ka ʻaina kakahiaka i ka huaʻōlelo i hoʻolauna mua ʻia. ʻO ka kuke ʻana i ka ʻaina kakahiaka ma kēia ʻano hoʻohālike he hana.

I ka hoʻomākaukau ʻana i ka ʻaina kakahiaka i ke kakahiaka (CPU) Hele mai au i ka lumi kuke (Kikokele). He 2 ko'u mau lima (Kora naʻEsau). Aia kekahi mau mea hana ma ka lumi kuke (IO): umu, ipu kīʻaha, mea hoʻoheheʻe, pahu hau. Hoʻā wau i ke kinoea, kau i ka pā palai a ninini i ka ʻaila i loko me ke kali ʻole e wela (asynchronously, Paʻa ʻole-IO-Kali), Wehe au i nā hua mai loko mai o ka friji a wāwahi i loko o kahi pā, a laila hahau iā lākou me ka lima hoʻokahi (Loko #1), a me ka lua (Loko #2) e paʻa ana i ka pā (Shared Resource). I kēia manawa makemake wau e hoʻā i ka ipu hao, akā ʻaʻole lawa koʻu mau lima (Pōloli Uila) I loko o kēia manawa, wela ka pā palai (Ka hana ʻana i ka hopena) kahi aʻu e ninini ai i ka mea aʻu i hahau ai. Lawe au i ka ipu hao a hoʻā a nānā naʻaupō i ka paila o ka wai i loko (Kāohi-IO-Kali), ʻoiai ua hiki iā ia ke holoi i ka pā kahi āna i hahau ai i ka omelet.

Hoʻomoʻa wau i ka omelete me ka hoʻohana ʻana i nā lima ʻelua wale nō, ʻaʻohe aʻu mea hou aku, akā i ka manawa like, i ka manawa o ka hahau ʻana i ka omelet, 2 mau hana i hana ʻia i ka manawa hoʻokahi: hahau i ka omelette, paʻa i ka pā, hoʻomehana i ka pā palai. ʻO ka CPU ka hapa wikiwiki loa o ka lolouila, ʻo IO ka mea e lohi pinepine ai nā mea a pau, no laila ʻo ka hopena maikaʻi loa ka hoʻopaʻa ʻana i ka CPU me kekahi mea i ka wā e loaʻa ai ka ʻikepili mai IO.

Ke hoʻomau nei i ka metaphor:

  • Inā ma ke kaʻina hana o ka hoʻomākaukau ʻana i kahi omelet, e hoʻāʻo pū wau e hoʻololi i nā lole, he laʻana kēia o ka multitasking. He nuance koʻikoʻi: ʻoi aku ka maikaʻi o nā kamepiula ma mua o nā kānaka.
  • ʻO kahi lumi kuke me kekahi mau chefs, no ka laʻana i loko o kahi hale ʻaina - he kamepiula multi-core.
  • Nui nā hale ʻaina i loko o kahi pāʻina meaʻai ma kahi kikowaena kūʻai - kikowaena data

.NET Mea Hana

Maikaʻi ʻo NET i ka hana ʻana me nā pae, e like me nā mea ʻē aʻe he nui. Me kēlā me kēia mana hou, hoʻolauna ia i nā mea hana hou aʻe no ka hana pū ʻana me lākou, nā papa hou o ka abstraction ma luna o nā pae OS. I ka hana ʻana me ke kūkulu ʻana i nā abstractions, hoʻohana nā mea hoʻomohala framework i kahi ala e waiho ai i ka manawa, i ka wā e hoʻohana ai i kahi abstraction kiʻekiʻe, e iho i lalo i hoʻokahi a ʻoi aku paha nā pae ma lalo. ʻO ka hapanui pinepine ʻaʻole pono kēia, ʻoiaʻiʻo, wehe ia i ka puka e pana iā ʻoe iho i ka wāwae me kahi pū pana, akā i kekahi manawa, i nā hihia liʻiliʻi, ʻo ia wale nō ke ala e hoʻoponopono ai i kahi pilikia ʻaʻole i hoʻoholo ʻia i ka pae o ka abstraction. .

Ma nā mea paahana, ʻo wau ke ʻōlelo nei i nā interface programme application (API) i hāʻawi ʻia e ka framework a me nā pūʻulu ʻaoʻao ʻekolu, a me nā ʻōnaehana polokalamu holoʻokoʻa e hoʻomaʻamaʻa i ka ʻimi ʻana i nā pilikia e pili ana i nā code multi-threaded.

E hoʻomaka ana i kahi pae

ʻO ka papa Thread ka papa maʻamau ma .NET no ka hana ʻana me nā pae. ʻAe ka mea kūkulu hale i kekahi o nā ʻelele ʻelua:

  • ThreadStart — ʻAʻohe palena
  • ParametrizedThreadStart - me hoʻokahi ʻāpana o ke ʻano mea.

E hoʻokō ʻia ka ʻelele ma ka pae hou i hana ʻia ma hope o ke kāhea ʻana i ke ʻano Start. Pono kēia ʻano hana e hoʻoili i nā ʻike kūloko i ke kahawai. He mea pono e hoʻomaopopo i ka hana ʻana i kahi kaula he hana koʻikoʻi, a ʻo ke kaula ponoʻī he mea koʻikoʻi, ma ka liʻiliʻi loa no ka mea e hoʻokaʻawale i ka 1MB o ka hoʻomanaʻo ma ka waihona a koi aku i ka pilina me ka OS API.

new Thread(...).Start(...);

Hōʻike ka papa ThreadPool i ka manaʻo o kahi loko. Ma .NET, he ʻāpana o ka ʻenekinia ka wai puna, a ua hoʻoikaika nui nā mea hoʻomohala ma Microsoft e hōʻoia i ka hana maikaʻi loa i nā ʻano hiʻohiʻona.

Manaʻo maʻamau:

Mai ka manawa e hoʻomaka ai ka noi, hana ia i kekahi mau kaula i mālama ʻia ma ke kua a hāʻawi i ka hiki ke lawe iā lākou no ka hoʻohana. Inā hoʻohana pinepine ʻia nā milo a me nā helu nui, hoʻonui ka loko i mea e pono ai ka mea kelepona. Inā ʻaʻohe wili manuahi i loko o ka loko i ka manawa kūpono, e kali paha ia no ka hoʻi ʻana mai o kekahi o nā milo, a i ʻole e hana i kahi mea hou. Ma muli o ia mea he mea maikaʻi ke kolamu thread no kekahi mau hana pōkole a kūpono ʻole no nā hana e holo ana ma ke ʻano he lawelawe i ka hana holoʻokoʻa o ka noi.

No ka hoʻohana ʻana i kahi kaula mai ka loko wai, aia kahi ala QueueUserWorkItem e ʻae i kahi ʻelele o ke ʻano WaitCallback, nona ka pūlima like me ParametrizedThreadStart, a ʻo ka ʻāpana i hāʻawi ʻia iā ia e hana i ka hana like.

ThreadPool.QueueUserWorkItem(...);

Hoʻohana ʻia ke ʻano wai puna liʻiliʻi i ʻike ʻia ʻo RegisterWaitForSingleObject no ka hoʻonohonoho ʻana i nā hana IO pale ʻole. E kāhea ʻia ka ʻelele i hāʻawi ʻia i kēia ʻano i ka wā i hele ai ka WaitHandle i ke ʻano "Hoʻokuʻu ʻia".

ThreadPool.RegisterWaitForSingleObject(...)

Loaʻa i ka NET kahi manawa pae a ʻokoʻa ia mai nā manawa WinForms/WPF no ka mea e kāhea ʻia kāna mea lawelawe ma kahi kaula i lawe ʻia mai ka loko.

System.Threading.Timer

Aia kekahi ala ʻē aʻe e hoʻouna ai i ʻelele no ka hoʻokō ʻana i kahi kaula mai ka loko wai - ke ʻano BeginInvoke.

DelegateInstance.BeginInvoke

Makemake wau e noʻonoʻo pōkole i ka hana i hiki ke kapa ʻia nā ʻano hana i luna - CreateThread mai Kernel32.dll Win32 API. Aia kahi ala, mahalo i ke ʻano o nā ʻano o waho, e kāhea i kēia hana. Ua ʻike wau i kēlā kelepona i hoʻokahi manawa wale nō i kahi hiʻohiʻona weliweli o ke code hoʻoilina, a ʻo ka hoʻoikaika ʻana o ka mea kākau i hana pololei i kēia mea e mau nei iaʻu he mea pohihihi.

Kernel32.dll CreateThread

Nānā a Debugging Threads

Hiki ke ʻike ʻia nā pae i hana ʻia e ʻoe, nā ʻāpana ʻaoʻao ʻekolu, a me ka punawai .NET ma ka pukaaniani Threads o Visual Studio. E hōʻike wale ana kēia puka makani i ka ʻike pili i ka wā e hoʻopau ʻia ai ka noi a ma ke ʻano Break. Maʻaneʻi hiki iā ʻoe ke nānā pono i nā inoa hoʻopaʻa a me nā mea nui o kēlā me kēia pae, a hoʻololi i ka debugging i kahi pae kikoʻī. Me ka hoʻohana ʻana i ka waiwai Priority o ka papa Thread, hiki iā ʻoe ke hoʻonohonoho i ka mea nui o kahi thread, i ʻike ʻia e ka OC a me CLR ma ke ʻano he ʻōlelo paipai i ka wā e puʻunaue ana i ka manawa kaʻina hana ma waena o nā kaula.

.NET: Mea hana no ka hana me ka multithreading a me ka asynchrony. Mahele 1

Hale Waihona Puke Kaulike

Ua hoʻokomo ʻia ʻo Task Parallel Library (TPL) ma .NET 4.0. ʻO kēia ka mea maʻamau a me ka mea hana nui no ka hana ʻana me asynchrony. ʻO kēlā me kēia code e hoʻohana ana i kahi ala kahiko i manaʻo ʻia he hoʻoilina. ʻO ka ʻāpana kumu o TPL ka papa hana mai ka System.Threading.Tasks namespace. ʻO kahi hana he abstraction ma luna o kahi thread. Me ka mana hou o ka ʻōlelo C#, loaʻa iā mākou kahi ala nani e hana pū ai me Tasks - async/await operators. Ua hiki i kēia mau manaʻo ke kākau i nā code asynchronous e like me ka maʻalahi a me ka synchronous, hiki i ka poʻe me ka ʻike liʻiliʻi i ka hana o loko o nā kaula e kākau i nā noi e hoʻohana ana iā lākou, nā noi ʻaʻole e maloʻo i ka wā e hana ana i nā hana lōʻihi. ʻO ka hoʻohana ʻana i ka async/wait he kumuhana no hoʻokahi a i ʻole kekahi mau ʻatikala, akā e hoʻāʻo wau e kiʻi i ke kumu o ia mea i kekahi mau ʻōlelo:

  • ʻO async kahi mea hoʻololi o kahi ala e hoʻihoʻi ana i ka Task a i ʻole ʻole
  • a ʻo ke kali ʻana he mea hoʻohana ʻole e hoʻopaʻa ʻia i ka hana kali.

Eia hou: ʻo ka mea hoʻohana kali, ma ka hihia maʻamau (he mau ʻokoʻa), e hoʻokuʻu hou i ke kaula o ka hoʻokō ʻana i kēia manawa, a ke hoʻopau ka Task i kāna hoʻokō ʻana, a me ke kaula (ʻoiaʻiʻo, ʻoi aku ka pololei o ka ʻōlelo ʻana i ka pōʻaiapili. , akā ʻoi aku ka nui o kēlā ma hope) e hoʻomau i ka hoʻokō ʻana i ke ʻano. I loko o .NET, hoʻokō ʻia kēia ʻano hana e like me ka hoʻihoʻi ʻana, i ka wā e lilo ai ke ʻano kākau i papa holoʻokoʻa, ʻo ia ka mīkini mokuʻāina a hiki ke hoʻokō ʻia i nā ʻāpana ʻokoʻa ma muli o kēia mau mokuʻāina. Hiki i nā mea makemake ke kākau i kekahi code maʻalahi me ka hoʻohana ʻana i ka asynс/await, hōʻuluʻulu a nānā i ka ʻaha me ka JetBrains dotPeek me ka Compiler Generated Code.

E nānā i nā koho no ka hoʻomaka ʻana a me ka hoʻohana ʻana i kahi Task. Ma ka laʻana code ma lalo nei, hana mākou i kahi hana hou ʻaʻohe mea pono (Loko.Sleep(10000)), akā i ke ola maoli he hana koʻikoʻi CPU kēia.

using TCO = System.Threading.Tasks.TaskCreationOptions;

public static async void VoidAsyncMethod() {
    var cancellationSource = new CancellationTokenSource();

    await Task.Factory.StartNew(
        // Code of action will be executed on other context
        () => Thread.Sleep(10000),
        cancellationSource.Token,
        TCO.LongRunning | TCO.AttachedToParent | TCO.PreferFairness,
        scheduler
    );

    //  Code after await will be executed on captured context
}

Hana ʻia kahi hana me nā koho he nui:

  • He hōʻailona ʻo LongRunning ʻaʻole e hoʻopau koke ʻia ka hana, ʻo ia hoʻi he mea kūpono e noʻonoʻo ʻole e lawe i kahi kaula mai ka loko wai, akā e hana i kahi ʻokoʻa no kēia Hana i ʻole e hōʻeha i kekahi.
  • AttachedToParent - Hiki ke hoʻonohonoho ʻia nā hana ma kahi hierarchy. Inā hoʻohana ʻia kēia koho, a laila aia paha ka Task ma kahi mokuʻāina kahi i hoʻopau ai a ke kali nei no ka hoʻokō ʻana i kāna mau keiki.
  • PreferFairness - ʻoi aku ka maikaʻi o ka hoʻokō ʻana i nā hana i hoʻouna ʻia no ka hoʻokō ʻana ma mua o nā mea i hoʻouna ʻia ma hope. Akā he ʻōlelo paipai wale nō kēia a ʻaʻole hōʻoia ʻia nā hopena.

ʻO ka ʻāpana ʻelua i hāʻawi ʻia i ke ala ʻo CancellationToken. No ka mālama pono ʻana i ka hoʻopau ʻana i kahi hana ma hope o ka hoʻomaka ʻana, pono e hoʻopiha ʻia ke code e hoʻokō ʻia me nā loiloi no ka mokuʻāina ʻo CancellationToken. Inā ʻaʻohe mākaʻikaʻi, a laila hiki i ke ala Hoʻopau i kapa ʻia ma ka mea CancellationTokenSource e hiki ke hoʻōki i ka hoʻokō ʻana i ka hana ma mua o ka hoʻomaka ʻana.

ʻO ka palena hope he mea hoʻonohonoho o ke ʻano TaskScheduler. Hoʻolālā ʻia kēia papa a me kāna poʻe mamo e hoʻokele i nā hoʻolālā no ka puʻunaue ʻana i nā hana ma nā loina; ma ke ʻano maʻamau, e hoʻokō ʻia ka Task ma kahi pae maʻamau mai ka loko.

Hoʻohana ʻia ka mea hoʻohana kali i ka Task i hana ʻia, ʻo ia hoʻi ke code i kākau ʻia ma hope o ia, inā he hoʻokahi, e hoʻokō ʻia ma ka pōʻaiapili like (pinepine ʻia kēia ma ka pae hoʻokahi) e like me ke code ma mua o ka kali.

Hōʻailona ʻia ke ʻano he async void, ʻo ia ka mea hiki ke hoʻohana i ka mea hoʻohana kali, akā ʻaʻole hiki i ke code kelepona ke kali no ka hoʻokō. Inā pono ia ʻano hiʻohiʻona, pono e hoʻihoʻi ke ala i ka Task. ʻO nā ʻano hana i hōʻailona ʻia async void he mea maʻamau: ma ke ʻano he kānāwai, ʻo ia nā mea lawelawe hanana a i ʻole nā ​​​​ʻano hana ʻē aʻe e hana ana i ke ahi a poina i ke kumu. Inā ʻaʻole pono ʻoe e hāʻawi i ka manawa e kali a hiki i ka hopena o ka hoʻokō, akā e hoʻihoʻi i ka hopena, a laila pono ʻoe e hoʻohana i ka Task.

Ma ka Task i hoʻihoʻi ʻia ke ʻano StartNew, a me nā mea ʻē aʻe, hiki iā ʻoe ke kāhea i ke ʻano ConfigureAwait me ka hoʻohālikelike hoʻopunipuni, a laila e hoʻomau ʻia ka hoʻokō ʻana ma hope o ke kali ʻana ma ka pōʻaiapili hopu ʻia, akā ma kahi ʻano ʻole. Pono e hana ʻia kēia inā ʻaʻole koʻikoʻi ka pōʻaiapili hoʻokō no ke code ma hope o ke kali ʻana. He ʻōlelo paipai nō hoʻi kēia mai MS i ke kākau ʻana i nā code e hāʻawi ʻia i loko o kahi waihona.

E noʻonoʻo hou kāua pehea ʻoe e kali ai no ka pau ʻana o kahi hana. Aia ma lalo kahi laʻana o ke code, me nā manaʻo i ka wā i hana maikaʻi ʻia ai ka manaʻolana a i ka wā i hana maikaʻi ʻole ʻia ai.

public static async void AnotherMethod() {

    int result = await AsyncMethod(); // good

    result = AsyncMethod().Result; // bad

    AsyncMethod().Wait(); // bad

    IEnumerable<Task> tasks = new Task[] {
        AsyncMethod(), OtherAsyncMethod()
    };

    await Task.WhenAll(tasks); // good
    await Task.WhenAny(tasks); // good

    Task.WaitAll(tasks.ToArray()); // bad
}

I ka laʻana mua, ke kali nei mākou no ka hoʻopau ʻana o ka Task me ka ʻole o ka pale ʻana i ke kaula kelepona; e hoʻi mākou i ka hoʻoponopono ʻana i ka hopena inā aia wale nō ia; a hiki i kēlā manawa, waiho ʻia ke kaula kelepona i kāna mau mea ponoʻī.

Ma ke koho ʻelua, hoʻopaʻa mākou i ke kaula kelepona a hiki i ka helu ʻana o ka hopena o ke ʻano. ʻAʻole maikaʻi kēia no ka mea ua paʻa mākou i kahi pae, kahi kumu waiwai nui o ka papahana, me ka palaualelo maʻalahi, akā no ka mea inā e kali ana ke code o ke ʻano a mākou e kāhea ai, a ʻo ka pōʻaiapili synchronization pono e hoʻi i ke kaula kelepona ma hope. e kali, a laila e loaʻa iā mākou kahi paʻa: Ke kali nei ke kaula kelepona i ka hopena o ke ʻano asynchronous e helu ʻia, hoʻāʻo ʻole ke ʻano asynchronous e hoʻomau i kāna hoʻokō ʻana i ke kaula kelepona.

ʻO kekahi hemahema o kēia ala ʻo ia ka paʻakikī o ka hana hewa. ʻO ka ʻoiaʻiʻo, ʻo nā hewa i ka code asynchronous i ka wā e hoʻohana ai i ka async/wait he maʻalahi loa ke mālama - ʻano like lākou me ke ʻano o ke code. ʻOiai inā mākou e hoʻohana i ka exorcism kali synchronous i kahi Task, ua lilo ka ʻokoʻa kumu i kahi AggregateException, ʻo ia. No ka mālama ʻana i ka ʻokoʻa, pono ʻoe e nānā i ke ʻano InnerException a kākau i kahi kaulahao inā ʻoe i loko o hoʻokahi pahu hopu a hoʻohana paha i ka hopu i ka wā e kūkulu ai, ma kahi o ke kaulahao o nā poloka hopu i maʻa i ka honua C#.

ʻO ke kolu a me nā hiʻohiʻona hope e hōʻailona maikaʻi ʻia no ke kumu like a loaʻa nā pilikia like a pau.

He mea maʻalahi nā ala WhenAny a me WhenAll no ke kali ʻana i kahi pūʻulu o nā Tasks; hoʻopili lākou i kahi pūʻulu o nā Hana i hoʻokahi, e puhi ʻia i ka wā i hoʻomaka mua ʻia ai kahi Task mai ka hui, a i ʻole i ka pau ʻana o kā lākou hana.

Ke hooki nei i nā kaula

No nā kumu like ʻole, pono paha e hoʻōki i ke kahe ma hope o ka hoʻomaka ʻana. Nui nā ala e hana ai i kēia. ʻElua mau ala i kapa ʻia i ka papa Thread: Hoopau и Hoʻopau. ʻAʻole ʻōlelo ʻia ka mea mua no ka hoʻohana ʻana, no ka mea ma hope o ke kāhea ʻana iā ia i kēlā me kēia manawa, i ka wā o ka hana ʻana i kekahi aʻo, e hoʻolei ʻia kahi ʻokoʻa ThreadAbortedException. ʻAʻole ʻoe e manaʻo e hoʻolei ʻia kahi ʻokoʻa i ka wā e hoʻonui ai i kekahi ʻano helu integer, pololei? A i ka hoʻohana ʻana i kēia ʻano, he kūlana maoli kēia. Inā pono ʻoe e pale i ka CLR mai ka hana ʻana i kēlā ʻano ʻokoʻa i kekahi ʻāpana o ke code, hiki iā ʻoe ke hoʻopili iā ia i nā kelepona. Thread.BeginCriticalRegion, Thread.EndCriticalRegion. Hoʻopili ʻia kēlā me kēia code i kākau ʻia i loko o kahi poloka hope i nā kelepona. No kēia kumu, ma ka hohonu o ke code framework hiki iā ʻoe ke loaʻa nā poloka me ka hoʻāʻo ʻole, akā ʻaʻole i ka hope loa. ʻAʻole i hoʻokomo ʻo Microsoft i kēia ʻano hana i loko o ka .net core.

ʻOi aku ka wānana o ke ʻano Interrupt. Hiki iā ia ke hoʻopau i ke kaula me ka ʻokoʻa ThreadInterruptedException i loko o kēlā mau manawa wale nō e kali ana ke kaula. Hoʻokomo ʻo ia i kēia mokuʻāina i ka wā e kali ana iā WaitHandle, laka, a i ʻole ma hope o ke kāhea ʻana iā Thread.Sleep.

ʻO nā koho ʻelua i hōʻike ʻia ma luna nei he hewa ma muli o ko lākou hiki ʻole ke wānana. ʻO ka hoʻonā ka hoʻohana ʻana i kahi hale HoʻopauToken a me ka papa HoʻopauTokenSource. ʻO ke kumu kēia: ua hana ʻia kahi ʻano o ka papa CancellationTokenSource a ʻo ka mea nona ka mea hiki ke hoʻōki i ka hana ma ke kāhea ʻana i ke ʻano. Ho'ōki. ʻO ka CancellationToken wale nō i hāʻawi ʻia i ka hana ponoʻī. ʻAʻole hiki i nā mea nona ka CancellationToken ke hoʻopau i ka hana iā lākou iho, akā hiki ke nānā wale inā ua kāpae ʻia ka hana. Aia kahi waiwai Boolean no kēia Noi ʻia ʻo IsCancellation a me ke ʻano ThrowIfCancelRequested. E hoʻolei ka hope i kahi ʻokoʻa TaskCancelledException inā ua kāhea ʻia ke ʻano hoʻokaʻawale ma ke ʻano o CancellationToken i hoʻopaʻa ʻia. A ʻo kēia ke ala aʻu e paipai nei e hoʻohana. He hoʻomaikaʻi kēia ma mua o nā koho mua ma o ka loaʻa ʻana o ka mana piha i ka manawa e hiki ke hoʻopau ʻia kahi hana ʻokoʻa.

ʻO ke koho koʻikoʻi loa no ka hoʻōki ʻana i kahi kaula e kāhea i ka hana Win32 API TerminateThread. ʻAʻole hiki ke ʻike ʻia ke ʻano o ka CLR ma hope o ke kāhea ʻana i kēia hana. Ma MSDN ua kākau ʻia kēia e pili ana i kēia hana: "He hana weliweli ka TerminateThread e hoʻohana wale ʻia i nā hihia koʻikoʻi loa. “

Ke hoʻololi nei i ka API hoʻoilina i ka Task Based me ka hoʻohana ʻana i ke ala FromAsync

Inā laki ʻoe i ka hana ʻana i kahi papahana i hoʻomaka ʻia ma hope o ka hoʻokomo ʻia ʻana o Tasks a hoʻopau i ka hoʻoweliweli mālie no ka hapa nui o nā mea hoʻomohala, a laila ʻaʻole pono ʻoe e hana me nā API kahiko, nā ʻaoʻao ʻekolu a me kāu hui. ua hoʻomāinoino i ka wā i hala. ʻO ka mea pōmaikaʻi, ua mālama ka hui .NET Framework iā mākou, ʻoiai paha ka pahuhopu e mālama iā mākou iho. E like me ka mea, .NET he mau mea paahana no ka painlessly hoohuli code i kakauia ma kahiko asynchronous polokalamu hoʻokokoke mai i ka hou. ʻO kekahi o lākou ʻo ke ala FromAsync o TaskFactory. Ma ka laʻana code ma lalo nei, hoʻopili wau i nā ala async kahiko o ka papa WebRequest i kahi Task me ka hoʻohana ʻana i kēia ʻano.

object state = null;
WebRequest wr = WebRequest.CreateHttp("http://github.com");
await Task.Factory.FromAsync(
    wr.BeginGetResponse,
    we.EndGetResponse
);

He laʻana wale nō kēia a ʻaʻole paha ʻoe e hana i kēia me nā ʻano i kūkulu ʻia, akā ʻo kekahi papahana kahiko e hoʻopiha wale ana me nā ala BeginDoSomething e hoʻihoʻi i nā ala IAsyncResult a me EndDoSomething e loaʻa ai.

E hoʻololi i ka API hoʻoilina i Task Based me ka hoʻohana ʻana i ka papa TaskCompletionSource

ʻO kekahi mea hana nui e noʻonoʻo ai ʻo ia ka papa Pūnaehana Hoʻopau. Ma ke ʻano o nā hana, ke kumu a me ke kumu o ka hana, hoʻomanaʻo paha ia i ke ʻano RegisterWaitForSingleObject o ka papa ThreadPool, aʻu i kākau ai ma luna. Ke hoʻohana nei i kēia papa, hiki iā ʻoe ke hoʻopili maʻalahi a maʻalahi hoʻi i nā API asynchronous kahiko ma Tasks.

E ʻōlelo ʻoe ua kamaʻilio mua wau e pili ana i ke ala FromAsync o ka papa TaskFactory i manaʻo ʻia no kēia mau kumu. Ma ʻaneʻi e hoʻomanaʻo mākou i ka mōʻaukala holoʻokoʻa o ka hoʻomohala ʻana i nā hiʻohiʻona asynchronous i .net i hāʻawi ʻia e Microsoft i nā makahiki he 15 i hala iho nei: ma mua o ka Task-Based Asynchronous Pattern (TAP), aia ka Asynchronous Programming Pattern (APP), ka mea. e pili ana i nā ʻano E hoʻomakaKe hoʻi nei kekahi mea IAsyncResult a me nā ʻano hana Ka pauʻO DoSomething e ʻae iā ia a no ka hoʻoilina o kēia mau makahiki ua kūpono ke ʻano FromAsync, akā i ka manawa lōʻihi, ua hoʻololi ʻia e ka Event Based Asynchronous Pattern (A ME AP), ka mea i manaʻo e hoʻāla ʻia kahi hanana ke pau ka hana asynchronous.

Kūpono ʻo TaskCompletionSource no ka hoʻopili ʻana i nā Tasks a me nā API hoʻoilina i kūkulu ʻia a puni ke kumu hoʻohālike. ʻO ke kumu o kāna hana penei: ʻo kahi mea o kēia papa he waiwai lehulehu o ke ʻano Task, hiki ke hoʻomalu ʻia ke kūlana ma o nā ʻano SetResult, SetException, etc. o ka papa TaskCompletionSource. Ma nā wahi i hoʻohana ʻia ai ka mea hoʻohana kali i kēia Task, e hoʻokō ʻia a hāʻule paha me kahi ʻokoʻa ma muli o ke ʻano i hoʻohana ʻia i ka TaskCompletionSource. Inā ʻaʻole maopopo, e nānā kākou i kēia laʻana code, kahi i kāʻei ʻia ai kekahi EAP API kahiko i kahi Task me ka TaskCompletionSource: ke ahi ka hanana, e hoʻoneʻe ʻia ka Task i ka mokuʻāina Completed, a me ke ʻano i hoʻohana ʻia i ka mea hoʻohana kali. i kēia Task e hoʻomau i kāna hoʻokō ʻana i ka loaʻa ʻana o ka mea result.

public static Task<Result> DoAsync(this SomeApiInstance someApiObj) {

    var completionSource = new TaskCompletionSource<Result>();
    someApiObj.Done += 
        result => completionSource.SetResult(result);
    someApiObj.Do();

    result completionSource.Task;
}

Nā ʻōlelo aʻoaʻo a me nā mea hoʻopunipuni TaskCompletionSource

ʻAʻole hiki ke hana ʻia me ka hoʻohana ʻana i TaskCompletionSource ka hoʻopili ʻana i nā API kahiko. Ke hoʻohana nei i kēia papa e wehe i kahi hiki ke hoʻolālā i nā API like ʻole ma nā hana i noho ʻole ʻia e nā kaula. A ʻo ke kahawai, e like me kā mākou e hoʻomanaʻo nei, he kumu waiwai nui a ua kaupalena ʻia kā lākou helu (ka nui o ka RAM). Hiki ke hoʻokō maʻalahi kēia palena ma ka hoʻomohala ʻana, no ka laʻana, kahi noi pūnaewele i hoʻouka ʻia me ka loiloi ʻoihana paʻakikī. E noʻonoʻo kākou i nā mea hiki aʻu e kamaʻilio nei i ka wā e hoʻokō ai i kahi hoʻopunipuni e like me Long-Polling.

I ka pōkole, ʻo ke ʻano o ka hoʻopunipuni kēia: pono ʻoe e loaʻa ka ʻike mai ka API e pili ana i kekahi mau hanana e kū nei ma kona ʻaoʻao, ʻoiai ʻo ka API, no kekahi kumu, ʻaʻole hiki ke hōʻike i ka hanana, akā hiki ke hoʻihoʻi i ka mokuʻāina. ʻO kahi laʻana o kēia mau API āpau i kūkulu ʻia ma luna o HTTP ma mua o ka manawa o WebSocket a i ʻole hiki ʻole ke hoʻohana i kēia ʻenehana. Hiki i ka mea kūʻai ke nīnau i ke kikowaena HTTP. ʻAʻole hiki i ka server HTTP ke hoʻomaka i ka kamaʻilio me ka mea kūʻai aku. ʻO kahi hoʻonā maʻalahi, ʻo ke koho balota ʻana i ke kikowaena me ka hoʻohana ʻana i ka manawa, akā hana kēia i kahi ukana hou ma ke kikowaena a me kahi lohi hou ma ka awelika TimerInterval / 2. ke kikowaena a hiki i ka pau ʻana o ka Timeout a i ʻole he hanana. Inā ua loaʻa ka hanana, a laila ua hana ʻia, inā ʻaʻole, a laila hoʻouna hou ʻia ke noi.

while(!eventOccures && !timeoutExceeded)  {

  CheckTimout();
  CheckEvent();
  Thread.Sleep(1);
}

Akā ʻo ia ʻano hopena e hōʻoia i ka weliweli i ka wā e piʻi ai ka nui o nā mea kūʻai aku e kali ana i ka hanana, no ka mea... Noho kēlā me kēia mea kūʻai aku i kahi pae holoʻokoʻa e kali ana i kahi hanana. ʻAe, a loaʻa iā mākou kahi lohi 1ms hou i ka wā e hoʻomaka ai ka hanana, ʻaʻole nui kēia, akā no ke aha e hoʻonui ai i ka polokalamu ma mua o ka hiki? Inā wehe mākou i ka Thread.Sleep(1), a laila makehewa mākou e hoʻouka i hoʻokahi kaʻina hana 100% idle, e hoʻololi ana i kahi pōʻai pono ʻole. Ke hoʻohana nei i TaskCompletionSource hiki iā ʻoe ke hana hou i kēia code a hoʻoponopono i nā pilikia āpau i ʻike ʻia ma luna.

class LongPollingApi {

    private Dictionary<int, TaskCompletionSource<Msg>> tasks;

    public async Task<Msg> AcceptMessageAsync(int userId, int duration) {

        var cs = new TaskCompletionSource<Msg>();
        tasks[userId] = cs;
        await Task.WhenAny(Task.Delay(duration), cs.Task);
        return cs.Task.IsCompleted ? cs.Task.Result : null;
    }

    public void SendMessage(int userId, Msg m) {

        if (tasks.TryGetValue(userId, out var completionSource))
            completionSource.SetResult(m);
    }
}

ʻAʻole mākaukau kēia code, akā he demo wale nō. No ka hoʻohana ʻana iā ia i nā hihia maoli, pono ʻoe, ma ka liʻiliʻi, e hoʻoponopono i ke kūlana ke hiki mai kahi leka i ka manawa i manaʻo ʻole ʻia e kekahi: i kēia hihia, pono e hoʻihoʻi ke ʻano AsseptMessageAsync i kahi hana i hoʻopau ʻia. Inā ʻo kēia ka hihia maʻamau, a laila hiki iā ʻoe ke noʻonoʻo e pili ana i ka hoʻohana ʻana iā ValueTask.

Ke loaʻa iā mākou kahi noi no kahi leka, hana mākou a kau i kahi TaskCompletionSource i loko o ka puke wehewehe ʻōlelo, a laila kali i ka mea e hana mua: pau ka manawa i ʻōlelo ʻia a loaʻa paha kahi leka.

ValueTask: no ke aha a pehea

ʻO nā mea hana async / kali, e like me ka mea hoʻihoʻi hoʻihoʻi, hoʻopuka i kahi mīkini mokuʻāina mai ke ʻano, a ʻo kēia ka hana ʻana i kahi mea hou, ʻaneʻane ʻaʻole ia he mea nui, akā i nā hihia liʻiliʻi hiki ke hana i kahi pilikia. ʻO kēia hihia ke ʻano i kapa pinepine ʻia, ke kamaʻilio nei mākou e pili ana i nā ʻumi a me nā haneli haneli o nā kelepona i kēlā me kēia kekona. Inā kākau ʻia kēlā ʻano hana i ka nui o nā hihia e hoʻihoʻi mai i kahi hopena ma mua o nā ala kali a pau, a laila hāʻawi ʻo .NET i kahi mea hana e hoʻomaikaʻi ai i kēia - ka ʻōnaehana ValueTask. No ka hoʻomaopopo ʻana, e nānā kākou i kahi laʻana o kona hoʻohana ʻana: aia kahi huna a mākou e hele pinepine ai. Aia kekahi mau waiwai i loko a laila hoʻihoʻi mākou iā lākou; inā ʻaʻole, a laila hele mākou i kahi IO lohi e kiʻi iā lākou. Makemake wau e hana i ka hope asynchronously, ʻo ia hoʻi ke ʻano holoʻokoʻa e lilo i asynchronous. No laila, ʻo ke ala maopopo e kākau ai i ke ʻano penei:

public async Task<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return val;
    return await RequestById(id);
}

Ma muli o ka makemake e hoʻonui iki, a me ka makaʻu iki i ka mea a Roslyn e hoʻopuka ai i ka wā e hōʻuluʻulu ai i kēia code, hiki iā ʻoe ke kākau hou i kēia hiʻohiʻona penei:

public Task<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return Task.FromResult(val);
    return RequestById(id);
}

ʻOiaʻiʻo, ʻo ka hopena maikaʻi loa i kēia hihia, ʻo ia ka hoʻonui ʻana i ke ala wela, ʻo ia hoʻi, ka loaʻa ʻana o ka waiwai mai ka puke wehewehe ʻōlelo me ka ʻole o nā hoʻokaʻawale pono ʻole a me ka hoʻouka ʻana i ka GC, ʻoiai i kēlā mau hihia koʻikoʻi ke pono mākou e hele i IO no ka ʻikepili. , e hoʻonui nā mea a pau i ke ala kahiko:

public ValueTask<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return new ValueTask<string>(val);
    return new ValueTask<string>(RequestById(id));
}

E nānā pono kākou i kēia ʻāpana code: inā he waiwai i loko o ka cache, hana mākou i kahi hoʻolālā, inā ʻaʻole e hoʻopili ʻia ka hana maoli i kahi mea koʻikoʻi. ʻAʻole mālama ke code kelepona i ke ala i hoʻokō ʻia ai kēia code: ValueTask, mai kahi C# syntax point of view, e hana like me ka hana maʻamau i kēia hihia.

TaskSchedulers: mālama i nā hoʻolālā hoʻomaka hana

ʻO ka API aʻe aʻu e makemake ai e noʻonoʻo ʻo ia ka papa Luna Hoʻonohonoho Hana a me kona mau mea i loaa mai. Ua ʻōlelo mua wau ma luna aʻe ua hiki iā TPL ke hoʻokele i nā hoʻolālā no ka hāʻawi ʻana i nā hana ma nā pae. Ua wehewehe ʻia kēlā mau hoʻolālā i nā mamo o ka papa TaskScheduler. Hiki ke loaʻa ma ka waihona ma kahi o nā hoʻolālā āu e makemake ai. ParallelExtensionsExtras, hoʻomohala ʻia e Microsoft, akā ʻaʻole ʻāpana o .NET, akā hāʻawi ʻia ma ke ʻano he pūʻolo Nuget. E nānā pōkole kākou i kekahi o lākou:

  • ʻO kēia manawaThreadTaskScheduler - hoʻokō i nā hana ma ka pae o kēia manawa
  • LimitedConcurrencyLevelTaskScheduler - palena i ka helu o nā hana i hoʻokō ʻia i ka manawa like e ka ʻāpana N, i ʻae ʻia i ka mea hana.
  • OrderedTaskScheduler — ua wehewehe ʻia ʻo LimitedConcurrencyLevelTaskScheduler(1), no laila e hoʻokō ʻia nā hana ma ke ʻano.
  • WorkStealingTaskScheduler - mea hana ʻaihue hana pili i ka mahele hana. ʻO ka mea nui he ThreadPool kaʻawale. Hoʻoholo i ka pilikia i loko o .NET ThreadPool he papa paʻa, hoʻokahi no nā noi āpau, ʻo ia hoʻi, ʻo kona hoʻohana nui ʻana a i ʻole ka hoʻohana hewa ʻana i kekahi ʻāpana o ka papahana hiki ke alakaʻi i nā hopena ʻaoʻao i kekahi. Eia kekahi, paʻakikī loa ka hoʻomaopopo ʻana i ke kumu o ia mau hemahema. ʻO kēlā. Pono paha e hoʻohana i nā WorkStealingTaskSchedulers ʻokoʻa ma nā ʻāpana o ka papahana kahi e hoʻohana ʻia ai ka ThreadPool i mea ʻino a ʻike ʻole ʻia.
  • QueuedTaskScheduler - hiki iā ʻoe ke hana i nā hana e like me nā lula queue priority
  • ThreadPerTaskScheduler - hana i kahi pae ʻokoʻa no kēlā me kēia hana i hana ʻia ma luna. Hiki ke hoʻohana i nā hana i lōʻihi ka manawa e hoʻopau ai.

Aia kahi kikoʻī maikaʻi 'atikala e pili ana i nā TaskSchedulers ma ka microsoft blog.

No ka hoʻopiʻi maʻalahi o nā mea a pau e pili ana i nā Tasks, loaʻa iā Visual Studio kahi puka makani Tasks. Ma kēia pukaaniani hiki iā ʻoe ke ʻike i ke kūlana o ka hana i kēia manawa a lele i ka laina code e hoʻokō nei i kēia manawa.

.NET: Mea hana no ka hana me ka multithreading a me ka asynchrony. Mahele 1

ʻO PLinq a me ka papa Parallel

Ma waho aʻe o nā hana a me nā mea a pau i ʻōlelo ʻia e pili ana iā lākou, aia ʻelua mau mea hana hoihoi ma .NET: PLinq (Linq2Parallel) a me ka papa Parallel. Hoʻohiki ka mua i ka hoʻokō like ʻana o nā hana Linq āpau ma nā pae he nui. Hiki ke hoʻonohonoho ʻia ka helu o nā kaula me ka hoʻohana ʻana i ke ala hoʻonui WithDegreeOfParallelism. ʻO ka mea pōʻino, ʻo ka hapa nui o PLinq i kāna ʻano paʻamau ʻaʻole lawa ka ʻike e pili ana i nā internals o kāu kumu ʻikepili e hāʻawi i ka loaʻa wikiwiki nui, ma kekahi ʻaoʻao, haʻahaʻa loa ke kumukūʻai o ka hoʻāʻo: pono ʻoe e kāhea i ke ala AsParallel ma mua. ke kaulahao o nā ʻano Linq a holo i nā hoʻokolohua hana. Eia kekahi, hiki ke hāʻawi i ka ʻike hou aku iā PLinq e pili ana i ke ʻano o kāu kumu ʻikepili me ka hoʻohana ʻana i ka mīkini Partitions. Hiki iā ʻoe ke heluhelu hou aku maanei и maanei.

Hāʻawi ka Parallel static class i nā ʻano no ka hoʻomaʻamaʻa ʻana ma o ka hōʻiliʻili Foreach i ka like, ka hoʻokō ʻana i ka loop For, a me ka hoʻokō ʻana i nā ʻelele he nui i ka Invoke like. Hoʻopau ʻia ka hoʻokō ʻana i ka pae o kēia manawa a pau ka helu ʻana. Hiki ke hoʻonohonoho ʻia ka helu o nā kaula ma ke kau ʻana iā ParallelOptions ma ke ʻano he hoʻopaʻapaʻa hope. Hiki iā ʻoe ke kuhikuhi i ka TaskScheduler a me CancellationToken me ka hoʻohana ʻana i nā koho.

haʻina

I koʻu hoʻomaka ʻana e kākau i kēia ʻatikala e pili ana i nā mea o kaʻu hōʻike a me nā ʻike aʻu i hōʻiliʻili ai i kaʻu hana ma hope o ia mea, ʻaʻole wau i manaʻo e nui ka nui o ia mea. I kēia manawa, ke haʻi mai nei ka mea hoʻoponopono kikokikona aʻu e paʻi nei i kēia ʻatikala iaʻu ua hala ka ʻaoʻao 15, e hōʻuluʻulu au i nā hopena manawa. ʻO nā hoʻopunipuni ʻē aʻe, nā API, nā mea hana ʻike a me nā pitfalls e uhi ʻia ma ka ʻatikala aʻe.

Nā hopena:

  • Pono ʻoe e ʻike i nā mea hana no ka hana ʻana me nā kaula, asynchrony a me ka parallelism i mea e hoʻohana ai i nā kumuwaiwai o nā PC hou.
  • He nui nā mea hana like ʻole o NET no kēia mau hana
  • ʻAʻole lākou a pau i ʻike ʻia i ka manawa hoʻokahi, no laila hiki iā ʻoe ke ʻike pinepine i nā mea hoʻoilina, akā naʻe, aia nā ala e hoʻohuli ai i nā API kahiko me ka ʻole o ka hoʻoikaika ʻana.
  • ʻO ka hana ʻana me nā pae ma .NET e hōʻike ʻia e nā papa Thread a me ThreadPool
  • ʻO ka Thread.Abort, Thread.Interrupt, a me Win32 API TerminateThread he mea weliweli a ʻaʻole ʻōlelo ʻia no ka hoʻohana. Akā, ʻoi aku ka maikaʻi o ka hoʻohana ʻana i ka mechanical CancellationToken
  • He waiwai waiwai ke kahe a ua kaupalena ʻia kāna lako. Pono e hōʻalo ʻia nā kūlana kahi e paʻa ai nā kaula e kali ana i nā hanana. No kēia mea kūpono ke hoʻohana i ka papa TaskCompletionSource
  • ʻO nā mea hana .NET ikaika loa no ka hana ʻana me ka parallelism a me ka asynchrony ʻo Tasks.
  • Hoʻokō nā mea hana c# async/wait i ka manaʻo o ka kali ʻole-blocking
  • Hiki iā ʻoe ke hoʻomalu i ka hāʻawi ʻana i nā hana ma nā pae me ka hoʻohana ʻana i nā papa i loaʻa i ka TaskScheduler
  • Hiki ke hoʻohana ʻia ka ʻōnaehana ValueTask i ka hoʻonui ʻana i nā ala wela a me nā kaʻa hoʻomanaʻo
  • Hāʻawi nā Visual Studio's Tasks and Threads windows i ka nui o ka ʻike e pono ai no ka debugging multi-threaded a i ʻole asynchronous code
  • He mea hana maikaʻi ʻo PLinq, akā ʻaʻole lawa ka ʻike e pili ana i kāu kumu ʻikepili, akā hiki ke hoʻopaʻa ʻia me ka hoʻohana ʻana i ka mīkini hoʻokaʻawale.
  • E hoʻomau 'ia…

Source: www.habr.com

Pākuʻi i ka manaʻo hoʻopuka