ç§ã¯Habrã«é¢ãããªãªãžãã«ã®èšäºãå
¬éããŠããããã®ç¿»èš³ã¯ã³ãŒãã¬ãŒããµã€ãã«æ²èŒãããŠããŸã
ä»ããçµæãåŸ
ããã«äœããéåæã§å®è¡ããå¿
èŠæ§ãã倧èŠæš¡ãªäœæ¥ãè€æ°ã®ãŠãããã«åå²ããŠå®è¡ããå¿
èŠæ§ã¯ãã³ã³ãã¥ãŒã¿ãŒã®åºçŸä»¥åããååšããŠããŸããã 圌ãã®åºçŸã«ããããã®å¿
èŠæ§ãéåžžã«å
·äœçã«ãªããŸããã 2019 幎ã®ä»ãç§ã¯ 8 ã³ã¢ Intel Core ããã»ããµãŒãæèŒããã©ãããããã§ãã®èšäºãå
¥åããŠããŸãããã®ããã»ããµãŒã§ã¯ 8 ãè¶
ããããã»ã¹ã䞊åå®è¡ãããããã«å€ãã®ã¹ã¬ãããå®è¡ãããŠããŸãã è¿ãã«ã¯ãæ°å¹Žåã«è³Œå
¥ããã16 ã³ã¢ã®ããã»ããµãæèŒããå°ãã¿ããŒãããæºåž¯é»è©±ããããŸãã ããŒãå¥ãªãœãŒã¹ã«ã¯ãèè
ã 20 ã³ã¢ ããã»ããµãæèŒããä»å¹Žã®äž»åã¹ããŒããã©ã³ãè³è³ããèšäºããããªãæºèŒã§ãã MS Azure ã¯ã128 ã³ã¢ ããã»ããµãš 2 TB RAM ãæèŒããä»®æ³ãã·ã³ã XNUMX æéããã XNUMX ãã«æªæºã§æäŸããŸãã æ®å¿µãªãããã¹ã¬ããã®çžäºäœçšã管çã§ããªããã°ããã®èœåãæ倧éã«åŒãåºããŠæŽ»çšããããšã¯äžå¯èœã§ãã
çšèª
ããã»ã¹ - OS ãªããžã§ã¯ããåé¢ãããã¢ãã¬ã¹ç©ºéã«ã¯ã¹ã¬ãããå«ãŸããŸãã
糞 - OS ãªããžã§ã¯ããå®è¡ã®æå°åäœãããã»ã¹ã®äžéšãã¹ã¬ããã¯ããã»ã¹å
ã§ã¡ã¢ãªããã®ä»ã®ãªãœãŒã¹ãå
±æããŸãã
ãã«ãã¿ã¹ã¯ - OS ããããã£ãè€æ°ã®ããã»ã¹ãåæã«å®è¡ããæ©èœ
ãã«ãã³ã¢ - ããã»ããµã®ç¹æ§ãããŒã¿åŠçã«è€æ°ã®ã³ã¢ã䜿çšããæ©èœ
ãã«ãããã»ãã·ã³ã° - ã³ã³ãã¥ãŒã¿ã®ç¹æ§ãç©ççã«è€æ°ã®ããã»ããµãåæã«åäœãããèœå
ãã«ãã¹ã¬ããå â ããã»ã¹ã®ããããã£ãããŒã¿åŠçãè€æ°ã®ã¹ã¬ããã«åæ£ããæ©èœã
å¹³è¡åºŠ - åäœæéåœããè€æ°ã®ã¢ã¯ã·ã§ã³ãç©ççã«åæã«å®è¡ãã
éåææ§ â ãã®åŠçã®å®äºãåŸ
ããã«æäœãå®è¡ããŸããå®è¡çµæã¯åŸã§åŠçã§ããŸãã
æ¯å©
ãã¹ãŠã®å®çŸ©ãé©åã§ããããã§ã¯ãªããè¿œå ã®èª¬æãå¿ èŠãªå®çŸ©ãããã®ã§ãæ£åŒã«å°å ¥ãããçšèªã«æé£ã®èª¿çã«é¢ããæ¯å©ãè¿œå ããŸãã ãã®æ¯å©ã§ã¯ãæé£ãäœãããšã¯ããã»ã¹ã§ãã
æãæé£ã®æºåãããªããïŒCPU) ãããã³ã«æ¥ãŸã(ã³ã³ãã¥ãŒã¿ïŒã æã2æ¬ãããŸã(ã³ã¢ïŒã ãããã³ã«ã¯è²ã ãªæ©åšããããŸã(IOïŒïŒãªãŒãã³ãã±ãã«ãããŒã¹ã¿ãŒãå·èµåº«ã ã¬ã¹ãã€ããŠãã©ã€ãã³ã眮ããæž©ãŸãã®ãåŸ ããã«æ²¹ã泚ããŸãïŒéåæããã³ããããã³ã° IO åŸ æ©ïŒãå·èµåº«ããåµãåãåºããç¿ã«å²ããçæã§æº¶ããŸãïŒã¹ã¬ãã#1)ãããã³ XNUMX çªç® (ã¹ã¬ãã#2) ãã¬ãŒã (å ±æãªãœãŒã¹) ãä¿æããŸãã ããŠãã±ãã«ã®ã¹ã€ãããå ¥ãããã®ã§ãããæã足ããŸãã(ã¹ã¬ããã®é£¢é€ïŒ ãã®éã«ãã©ã€ãã³ãå ç±ãããŸãïŒçµæã®åŠçïŒãããã«æ³¡ç«ãŠããã®ã泚ããŸãã ç§ã¯ãããã«æã䌞ã°ããŠã¹ã€ãããå ¥ããæãã«ããã®äžã§æ°Žã沞隰ããã®ãçºããŸããïŒããããã³ã° IO åŸ æ©ïŒããã ãããã®éã«ãªã ã¬ãã泡ç«ãŠãç¿ãæŽãããšãã§ããŸããã
ãªã ã¬ããäž¡æã ãã§äœããŸãããããã以äžã¯ãããŸããããåæã«ããªã ã¬ãã泡ç«ãŠãç¬éã«ããªã ã¬ãã泡ç«ãŠããç¿ãæã€ããã©ã€ãã³ãå ç±ãããšãã2ã€ã®æäœãåæã«è¡ãããŸãã CPU ã¯ã³ã³ãã¥ãŒã¿ã®äžã§æãéãéšåã§ãããIO ã¯ã»ãšãã©ã®å Žåãã¹ãŠãé ããªãéšåã§ãããããå€ãã®å Žåå¹æçãªè§£æ±ºçã¯ãIO ããããŒã¿ãåä¿¡ããŠââããé CPU ãäœãã§å æããããšã§ãã
æ¯å©ã®ç¶ã:
- ãªã ã¬ããäœãéäžã§çæ¿ããããããšãããšãããã¯ãã«ãã¿ã¹ã¯ã®äžäŸã«ãªããŸãã éèŠãªãã¥ã¢ã³ã¹: ã³ã³ãã¥ãŒã¿ã¯ãã®ç¹ã§ã¯äººéãããã¯ããã«åªããŠããŸãã
- ã¬ã¹ãã©ã³ãªã©ãè€æ°ã®ã·ã§ãããããããã³ - ãã«ãã³ã¢ ã³ã³ãã¥ãŒã¿ãŒã
- ã·ã§ããã³ã° ã»ã³ã¿ãŒ - ããŒã¿ ã»ã³ã¿ãŒã®ããŒã ã³ãŒãã«ããå€ãã®ã¬ã¹ãã©ã³
.NETããŒã«
.NET ã¯ãä»ã®å€ãã®ãã®ãšåæ§ãã¹ã¬ããã®æäœã«åªããŠããŸãã æ°ããããŒãžã§ã³ãç»å Žãããã³ã«ãããããæäœããããã®æ°ããããŒã«ãOS ã¹ã¬ããäžã®æ°ããæœè±¡åã¬ã€ã€ãŒãã©ãã©ãå°å ¥ãããŠããŸãã æœè±¡åã®æ§ç¯ã«åãçµããšãããã¬ãŒã ã¯ãŒã¯éçºè ã¯ãé«ã¬ãã«ã®æœè±¡åã䜿çšãããšãã« XNUMX ã€ä»¥äžäžã®ã¬ãã«ã«é²ãæ©äŒãæ®ãã¢ãããŒãã䜿çšããŸãã ã»ãšãã©ã®å Žåãããã¯å¿ èŠãããŸãããå®éãã·ã§ããã¬ã³ã§èªåã®è¶³ãæã€å¯èœæ§ããããŸããããŸãã«ãçŸåšã®æœè±¡åã¬ãã«ã§ã¯è§£æ±ºã§ããªãåé¡ã解決ããå¯äžã®æ¹æ³ã§ããå ŽåããããŸãã ã
ããŒã«ãšã¯ããã¬ãŒã ã¯ãŒã¯ãšãµãŒãããŒãã£ã®ããã±ãŒãžã«ãã£ãŠæäŸãããã¢ããªã±ãŒã·ã§ã³ ããã°ã©ãã³ã° ã€ã³ã¿ãŒãã§ã€ã¹ (API) ã®äž¡æ¹ãšããã«ãã¹ã¬ãã ã³ãŒãã«é¢é£ããåé¡ã®æ€çŽ¢ãç°¡çŽ åãããœãããŠã§ã¢ ãœãªã¥ãŒã·ã§ã³å šäœãæå³ããŸãã
ã¹ã¬ãããéå§ãã
Thread ã¯ã©ã¹ã¯ãã¹ã¬ãããæäœããããã® .NET ã®æãåºæ¬çãªã¯ã©ã¹ã§ãã ã³ã³ã¹ãã©ã¯ã¿ãŒã¯ã次㮠XNUMX ã€ã®ããªã²ãŒãã®ãããããåãå ¥ããŸãã
- ThreadStart â ãã©ã¡ãŒã¿ãªã
- ParametrizedThreadStart - ãªããžã§ã¯ãåã®ãã©ã¡ãŒã¿ã XNUMX ã€ãããŸãã
ããªã²ãŒãã¯ãStart ã¡ãœãããåŒã³åºããåŸãæ°ããäœæãããã¹ã¬ããã§å®è¡ãããŸããParametrizedThreadStart åã®ããªã²ãŒããã³ã³ã¹ãã©ã¯ã¿ãŒã«æž¡ãããå Žåã¯ããªããžã§ã¯ãã Start ã¡ãœããã«æž¡ãå¿ èŠããããŸãã ãã®ã¡ã«ããºã ã¯ãããŒã«ã«æ å ±ãã¹ããªãŒã ã«è»¢éããããã«å¿ èŠã§ãã ã¹ã¬ããã®äœæã¯é«äŸ¡ãªæäœã§ãããå°ãªããšãã¹ã¿ãã¯äžã« 1MB ã®ã¡ã¢ãªãå²ãåœãŠãOS API ãšã®å¯Ÿè©±ãå¿ èŠãšãããããã¹ã¬ããèªäœãéããªããžã§ã¯ãã§ããããšã«æ³šæããŠãã ããã
new Thread(...).Start(...);
ThreadPool ã¯ã©ã¹ã¯ãããŒã«ã®æŠå¿µãè¡šããŸãã .NET ã§ã¯ãã¹ã¬ãã ããŒã«ã¯ãšã³ãžãã¢ãªã³ã°ã®äžéšã§ãããMicrosoft ã®éçºè ã¯ãã¹ã¬ãã ããŒã«ãããŸããŸãªã·ããªãªã§æé©ã«åäœããããã«å€å€§ãªåªåãæã£ãŠããŸããã
äžè¬çãªæŠå¿µ:
ã¢ããªã±ãŒã·ã§ã³ãèµ·åããç¬éãããããã¯ã°ã©ãŠã³ãã§ããã€ãã®ã¹ã¬ãããäºçŽããããããã䜿çšã§ããããã«ãªããŸãã ã¹ã¬ãããé »ç¹ãã€å€§éã«äœ¿çšãããå ŽåãåŒã³åºãå ã®ããŒãºãæºããããã«ããŒã«ãæ¡åŒµãããŸãã é©åãªã¿ã€ãã³ã°ã§ããŒã«ã«ç©ºãã¹ã¬ããããªãå Žåãã¹ã¬ããã® XNUMX ã€ãæ»ãã®ãåŸ ã€ããæ°ããã¹ã¬ãããäœæããŸãã ãããã£ãŠãã¹ã¬ãã ããŒã«ã¯äžéšã®çæçãªã¢ã¯ã·ã§ã³ã«ã¯é©ããŠããŸãããã¢ããªã±ãŒã·ã§ã³ã®æäœå šäœãéããŠãµãŒãã¹ãšããŠå®è¡ãããæäœã«ã¯ããŸãé©ããŠããŸããã
ããŒã«ã®ã¹ã¬ããã䜿çšããã«ã¯ãParametrizedThreadStart ãšåãã·ã°ããã£ãæ〠WaitCallback åã®ããªã²ãŒããåãå ¥ãã QueueUserWorkItem ã¡ãœããããããããã«æž¡ããããã©ã¡ãŒã¿ãŒã¯åãæ©èœãå®è¡ããŸãã
ThreadPool.QueueUserWorkItem(...);
ããŸãç¥ãããŠããªãã¹ã¬ãã ããŒã« ã¡ãœãã RegisterWaitForSingleObject ã¯ããã³ããããã³ã° IO æäœãç·šæããããã«äœ¿çšãããŸãã ãã®ã¡ãœããã«æž¡ãããããªã²ãŒãã¯ãã¡ãœããã«æž¡ããã WaitHandle ãããªãªãŒã¹ãããããšãã«åŒã³åºãããŸãã
ThreadPool.RegisterWaitForSingleObject(...)
.NET ã«ã¯ã¹ã¬ãã ã¿ã€ããŒãããããã®ãã³ãã©ãŒãããŒã«ããååŸãããã¹ã¬ããã§åŒã³åºããããšããç¹ã§ WinForms/WPF ã¿ã€ããŒãšã¯ç°ãªããŸãã
System.Threading.Timer
ããŒã«ããã¹ã¬ããã«å®è¡çšã®ããªã²ãŒããéä¿¡ããããªãå€ãã£ãæ¹æ³ãBeginInvoke ã¡ãœããããããŸãã
DelegateInstance.BeginInvoke
äžèšã®ã¡ãœããã®å€ããåŒã³åºãããšãã§ããé¢æ°ãã€ãŸã Kernel32.dll Win32 API ããã® CreateThread ã«ã€ããŠç°¡åã«èª¬æããããšæããŸãã extern ã¡ãœããã®ã¡ã«ããºã ã®ãããã§ããã®é¢æ°ãåŒã³åºãæ¹æ³ããããŸãã ç§ã¯ãã®ãããªåŒã³åºããã¬ã¬ã·ãŒ ã³ãŒãã®ã²ã©ãäŸã§äžåºŠã ãèŠãããšããããŸããããŸãã«ãããå®è¡ããäœè ã®åæ©ã¯ããŸã ã«è¬ã®ãŸãŸã§ãã
Kernel32.dll CreateThread
ã¹ã¬ããã®è¡šç€ºãšãããã°
ãŠãŒã¶ãŒãäœæããã¹ã¬ããããã¹ãŠã®ãµãŒãããŒã㣠ã³ã³ããŒãã³ããããã³ .NET ããŒã«ã¯ãVisual Studio ã® [ã¹ã¬ãã] ãŠã£ã³ããŠã§è¡šç€ºã§ããŸãã ãã®ãŠã£ã³ããŠã«ã¯ãã¢ããªã±ãŒã·ã§ã³ããããã°äžã§ãã¬ãŒã¯ ã¢ãŒãã«ããå Žåã«ã®ã¿ã¹ã¬ããæ å ±ã衚瀺ãããŸãã ããã§ã¯ãåã¹ã¬ããã®ã¹ã¿ãã¯åãšåªå é äœãç°¡åã«è¡šç€ºãããããã°ãç¹å®ã®ã¹ã¬ããã«åãæ¿ããããšãã§ããŸãã Thread ã¯ã©ã¹ã® Priority ããããã£ã䜿çšãããšãã¹ã¬ããã®åªå é äœãèšå®ã§ããŸãããã®åªå é äœã¯ãã¹ã¬ããéã§ããã»ããµæéãåå²ãããšãã« OC ããã³ CLR ãæšå¥šäºé ãšããŠèªèããŸãã
ã¿ã¹ã¯äžŠåã©ã€ãã©ãª
ã¿ã¹ã¯äžŠåã©ã€ãã©ãª (TPL) 㯠.NET 4.0 ã§å°å ¥ãããŸããã çŸåšãããã¯éåæãæäœããããã®æšæºãã€äž»èŠãªããŒã«ã§ãã å€ãã¢ãããŒãã䜿çšããã³ãŒãã¯ãã¹ãŠã¬ã¬ã·ãŒãšã¿ãªãããŸãã TPL ã®åºæ¬åäœã¯ãSystem.Threading.Tasks åå空éã® Task ã¯ã©ã¹ã§ãã ã¿ã¹ã¯ã¯ã¹ã¬ãããæœè±¡åãããã®ã§ãã C# èšèªã®æ°ããããŒãžã§ã³ã§ã¯ãã¿ã¹ã¯ (async/await æŒç®å) ãæŽç·Žãããæ¹æ³ã§æäœã§ããããã«ãªããŸããã ãããã®æŠå¿µã«ãããããããåçŽãªåæã§ãããã®ããã«éåæã³ãŒããäœæã§ããããã«ãªããã¹ã¬ããã®å éšåäœãã»ãšãã©ç解ããŠããªã人ã§ããéåæã³ãŒãã䜿çšããã¢ããªã±ãŒã·ã§ã³ãã€ãŸãé·æéã®æäœãå®è¡ããŠãããªãŒãºããªãã¢ããªã±ãŒã·ã§ã³ãäœæã§ããããã«ãªããŸããã async/await ã®äœ¿çšã¯ XNUMX ã€ãŸãã¯è€æ°ã®èšäºã®ãããã¯ã§ãããããã€ãã®æã§èŠç¹ãç解ããããšããŸãã
- async ã¯ãTask ãŸã㯠void ãè¿ãã¡ãœããã®ä¿®é£Ÿåã§ãã
- await ã¯ãã³ããããã³ã°ã®ã¿ã¹ã¯åŸ æ©æŒç®åã§ãã
ããäžåºŠèšããŸã: await ãªãã¬ãŒã¿ãŒã¯ãäžè¬çãªå Žå (äŸå€ããããŸã)ãçŸåšã®å®è¡ã¹ã¬ãããããã«è§£æŸããã¿ã¹ã¯ãå®è¡ãçµäºãããšãã¹ã¬ãã (å®éã«ã¯ã³ã³ããã¹ããšèšã£ãã»ããæ£ããã§ããã) ããã ã詳现ã¯åŸã»ã©) ã¡ãœããã®å®è¡ãããã«ç¶ããŸãã .NET å éšã§ã¯ããã®ã¡ã«ããºã ã¯ãæžãããã¡ãœãããã¹ããŒã ãã·ã³ã§ããã¯ã©ã¹å šäœã«ãªãããããã®ç¶æ ã«å¿ããŠåå¥ã«å®è¡ã§ãããyield return ãšåãæ¹æ³ã§å®è£ ãããŸãã èå³ã®ãã人ã¯èª°ã§ããasynÑ/await ã䜿çšããŠç°¡åãªã³ãŒããäœæããã³ã³ãã€ã©ãŒçæã³ãŒããæå¹ã«ã㊠JetBrains dotPeek ã䜿çšããŠã¢ã»ã³ããªãã³ã³ãã€ã«ãã衚瀺ããããšãã§ããŸãã
ã¿ã¹ã¯ãèµ·åããŠäœ¿çšããããã®ãªãã·ã§ã³ãèŠãŠã¿ãŸãããã 以äžã®ã³ãŒãäŸã§ã¯ãäœã圹ã«ç«ããªãæ°ããã¿ã¹ã¯ãäœæããŸã (ã¹ã¬ãã.ã¹ãªãŒã(10000)) ã§ãããå®éã«ã¯ããã㯠CPU ã倧éã«äœ¿çšããè€éãªäœæ¥ã«ãªãã¯ãã§ãã
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
}
ã¿ã¹ã¯ã¯ããã€ãã®ãªãã·ã§ã³ã䜿çšããŠäœæãããŸãã
- LongRunning ã¯ãã¿ã¹ã¯ãããã«ã¯å®äºããªãããšã瀺ããŠããŸããã€ãŸããããŒã«ããã¹ã¬ãããååŸãããä»ã®ã¿ã¹ã¯ã«å®³ãåãŒããªãããã«ããã®ã¿ã¹ã¯çšã«å¥ã®ã¹ã¬ãããäœæããããšãæ€èšãã䟡å€ãããå¯èœæ§ããããŸãã
- AttachedToParent - ã¿ã¹ã¯ãéå±€çã«é 眮ã§ããŸãã ãã®ãªãã·ã§ã³ã䜿çšãããå Žåãã¿ã¹ã¯ã¯ããèªäœãå®äºããåã®å®è¡ãåŸ ã£ãŠããç¶æ ã«ãªãå¯èœæ§ããããŸãã
- PreferFairness - å®è¡ã®ããã«éä¿¡ãããã¿ã¹ã¯ããåŸã§éä¿¡ãããã¿ã¹ã¯ãããå ã«å®è¡ããæ¹ãããããšãæå³ããŸãã ãã ããããã¯åãªãæšå¥šã§ãããçµæãä¿èšŒããããã®ã§ã¯ãããŸããã
ã¡ãœããã«æž¡ããã XNUMX çªç®ã®ãã©ã¡ãŒã¿ãŒã¯ CancelToken ã§ãã éå§åŸã®æäœã®ãã£ã³ã»ã«ãæ£ããåŠçããã«ã¯ãå®è¡äžã®ã³ãŒãã« cancelsToken ç¶æ ã®ãã§ãã¯ãåã蟌ãå¿ èŠããããŸãã ãã§ãã¯ããªãå ŽåãCancelTokenSource ãªããžã§ã¯ãã§åŒã³åºããã Cancel ã¡ãœããã¯ãã¿ã¹ã¯ã®å®è¡ãéå§åã«ã®ã¿åæ¢ã§ããŸãã
æåŸã®ãã©ã¡ãŒã¿ã¯ãTaskScheduler ã¿ã€ãã®ã¹ã±ãžã¥ãŒã© ãªããžã§ã¯ãã§ãã ãã®ã¯ã©ã¹ãšãã®åå«ã¯ãã¹ã¬ããéã§ã¿ã¹ã¯ãåæ£ããããã®æŠç¥ãå¶åŸ¡ããããã«èšèšãããŠãããããã©ã«ãã§ã¯ãã¿ã¹ã¯ã¯ããŒã«ããã®ã©ã³ãã ãªã¹ã¬ããã§å®è¡ãããŸãã
await æŒç®åã¯ãäœæãããã¿ã¹ã¯ã«é©çšãããŸããã€ãŸãããã®åŸã«èšè¿°ãããã³ãŒã (ååšããå Žå) ã¯ãawait åã®ã³ãŒããšåãã³ã³ããã¹ã (å€ãã®å Žåãåãã¹ã¬ããäžãæå³ããŸã) ã§å®è¡ãããŸãã
ãã®ã¡ãœãã㯠async void ãšããŠããŒã¯ãããŠããŸããããã¯ãawait æŒç®åã䜿çšã§ããŸãããåŒã³åºãå ã®ã³ãŒãã¯å®è¡ãåŸ æ©ã§ããªãããšãæå³ããŸãã ãã®ãããªæ©èœãå¿ èŠãªå Žåãã¡ãœãã㯠Task ãè¿ãå¿ èŠããããŸãã async void ãšããŒã¯ãããã¡ãœããã¯éåžžã«äžè¬çã§ããéåžžããããã¯ã€ãã³ã ãã³ãã©ãŒãŸãã¯ãã¡ã€ã¢ ã¢ã³ã ãã©ãŒã²ããã®ååã«åºã¥ããŠåäœãããã®ä»ã®ã¡ãœããã§ãã å®è¡ãçµäºãããŸã§åŸ æ©ããæ©äŒãäžããã ãã§ãªããçµæãè¿ãå¿ èŠãããå Žåã¯ãTask ã䜿çšããå¿ èŠããããŸãã
StartNew ã¡ãœãããè¿ããã¿ã¹ã¯ããã®ä»ã®ã¿ã¹ã¯ã§ã¯ãfalse ãã©ã¡ãŒã¿ãŒãæå®ã㊠ConfigureAwait ã¡ãœãããåŒã³åºãããšãã§ããŸããããããã°ãawait åŸã®å®è¡ã¯ãã£ããã£ãããã³ã³ããã¹ãã§ã¯ãªããä»»æã®ã³ã³ããã¹ãã§ç¶è¡ãããŸãã ããã¯ãawait åŸã®ã³ãŒãã«ãšã£ãŠå®è¡ã³ã³ããã¹ããéèŠã§ã¯ãªãå Žåã«åžžã«å®è¡ããå¿ èŠããããŸãã ããã¯ãã©ã€ãã©ãªã«ããã±ãŒãžåãããŠæäŸãããã³ãŒããäœæããå Žåã® MS ã®æšå¥šäºé ã§ããããŸãã
ã¿ã¹ã¯ã®å®äºãåŸ ã€æ¹æ³ã«ã€ããŠããå°ã詳ããèŠãŠã¿ãŸãããã 以äžã¯ãæåŸ ãæ¡ä»¶ä»ãã§é©åã«å®è¡ãããå Žåãšãæ¡ä»¶ä»ãã§é©åã«å®è¡ãããªãã£ãå Žåã«é¢ããã³ã¡ã³ããå«ãã³ãŒãã®äŸã§ãã
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
}
æåã®äŸã§ã¯ãåŒã³åºãã¹ã¬ããããããã¯ããã«ã¿ã¹ã¯ãå®äºããã®ãåŸ ã¡ãŸããçµæããã§ã«ååšããå Žåã«ã®ã¿çµæã®åŠçã«æ»ããŸãããããŸã§ãåŒã³åºãã¹ã¬ããã¯ç¬èªã®ããã€ã¹ã«æ®ãããŸãã
XNUMX çªç®ã®ãªãã·ã§ã³ã§ã¯ãã¡ãœããã®çµæãèšç®ããããŸã§åŒã³åºãã¹ã¬ããããããã¯ããŸãã ããã¯ãããã°ã©ã ã®è²ŽéãªãªãœãŒã¹ã§ããã¹ã¬ãããåçŽãªã¢ã€ãã«ç¶æ ã§å æããŠããããã ãã§ãªããåŒã³åºãã¡ãœããã®ã³ãŒãã« await ãå«ãŸããŠãããåæã³ã³ããã¹ããåŒã³åºãåŸã«åŒã³åºãã¹ã¬ããã«æ»ãå¿ èŠãããå Žåã«ãåé¡ã§ãã await, then we will get a Deadlock : åŒã³åºãã¹ã¬ããã¯éåæã¡ãœããã®çµæãèšç®ãããã®ãåŸ ã¡ãŸãããéåæã¡ãœããã¯åŒã³åºãã¹ã¬ããã§å®è¡ãç¶ç¶ããããšããŸããç¡é§ã§ãã
ãã®ã¢ãããŒãã®ãã XNUMX ã€ã®æ¬ ç¹ã¯ããšã©ãŒåŠçãè€éãªããšã§ãã å®éãasync/await ã䜿çšããå Žåã®éåæã³ãŒãã®ãšã©ãŒã¯éåžžã«ç°¡åã«åŠçã§ããã³ãŒããåæããŠããå Žåãšåãããã«åäœããŸãã äžæ¹ãã¿ã¹ã¯ã«åæåŸ æ©æé€ãé©çšãããšãå ã®äŸå€ã¯ AggregateException ã«å€ãããŸãã äŸå€ãåŠçããã«ã¯ãInnerException åã調ã¹ãŠãXNUMX ã€ã® catch ãããã¯å ã« if ãã§ãŒã³ãèªåã§èšè¿°ããããC# ã®äžçã§ããç¥ãããŠãã catch ãããã¯ã®ãã§ãŒã³ã®ä»£ããã« catch when ã³ã³ã¹ãã©ã¯ãã䜿çšããå¿ èŠããããŸãã
XNUMX çªç®ãšæåŸã®äŸãåãçç±ã§äžè¯ãšããŒã¯ãããŠããããã¹ãŠåãåé¡ãå«ãŸããŠããŸãã
WhenAny ã¡ãœãããš WhenAll ã¡ãœããã¯ãã¿ã¹ã¯ã®ã°ã«ãŒããåŸ æ©ããå Žåã«éåžžã«äŸ¿å©ã§ãããããã®ã¡ãœããã¯ãã¿ã¹ã¯ã®ã°ã«ãŒãã XNUMX ã€ã«ã©ããããã°ã«ãŒãã®ã¿ã¹ã¯ãæåã«ããªã¬ãŒããããšãããŸãã¯ãã¹ãŠã®ã¿ã¹ã¯ã®å®è¡ãå®äºãããšãã«èµ·åããŸãã
ã¹ã¬ããã®åæ¢
ããŸããŸãªçç±ã«ããããããŒãéå§ãããåŸã«ãããŒãåæ¢ããå¿ èŠãããå ŽåããããŸãã ãããè¡ãã«ã¯ããã€ãã®æ¹æ³ããããŸãã Thread ã¯ã©ã¹ã«ã¯ãé©åãªååãä»ãããã XNUMX ã€ã®ã¡ãœããããããŸãã æµç£ О å²ã蟌ã¿ã æåã®ãã®ã¯äœ¿çšããããšã匷ããå§ãããŸããã ã©ã³ãã ãªç¬éã«åŒã³åºããåŸãåœä»€ã®åŠçäžã«äŸå€ãã¹ããŒãããŸãã ã¹ã¬ããäžæ¢äŸå€ã æŽæ°å€æ°ãã€ã³ã¯ãªã¡ã³ããããšãã«ãã®ãããªäŸå€ãã¹ããŒããããšã¯äºæ³ããŸãããã? ãã®æ¹æ³ã䜿çšãããšããããéåžžã«çŸå®çãªç¶æ³ã«ãªããŸãã ã³ãŒãã®ç¹å®ã®ã»ã¯ã·ã§ã³ã§ CLR ããã®ãããªäŸå€ãçæããªãããã«ããå¿ èŠãããå Žåã¯ããããåŒã³åºãã§ã©ããã§ããŸãã Thread.BeginCriticalRegion, Thread.EndCriticalRegionã Final ãããââã¯ã«èšè¿°ãããã³ãŒãã¯ãã¹ãŠããã®ãããªåŒã³åºãã§ã©ãããããŸãã ãã®ããããã¬ãŒã ã¯ãŒã¯ ã³ãŒãã®å¥¥æ·±ãã§ã¯ã空㮠try ãæã€ãããã¯ã¯èŠã€ãããŸããã空㮠Finally ã¯èŠã€ãããŸããã Microsoft ã¯ãã®æ¹æ³ãéåžžã«æšå¥šããŠããªãããã.net core ã«ã¯å«ããŠããŸããã
Interrupt ã¡ãœããã¯ããäºæž¬ã©ããã«æ©èœããŸãã äŸå€ã«ããã¹ã¬ãããäžæããå¯èœæ§ããããŸã ã¹ã¬ããäžæäŸå€ ã¹ã¬ãããåŸ æ©ç¶æ ã«ãããšãã®ã¿ã WaitHandleãããã¯ã®åŸ æ©äžããŸã㯠Thread.Sleep ã®åŒã³åºãåŸã«ãã³ã°ããŠãããšãã«ãã®ç¶æ ã«ãªããŸãã
äžã§èª¬æããäž¡æ¹ã®ãªãã·ã§ã³ã¯ãäºæž¬äžå¯èœã§ãããã奜ãŸãããããŸããã 解決çã¯æ§é ã䜿çšããããšã§ã ãã£ã³ã»ã«ããŒã¯ã³ ãããŠã¯ã©ã¹ CancelTokenSourceã éèŠãªã®ã¯ãCancelTokenSource ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãäœæããããã®ã€ã³ã¹ã¿ã³ã¹ãææãã人ã ããã¡ãœãããåŒã³åºããŠæäœãåæ¢ã§ãããšããããšã§ãã ãã£ã³ã»ã«ã CancelToken ã®ã¿ããªãã¬ãŒã·ã§ã³èªäœã«æž¡ãããŸãã CancelToken ã®ææè ã¯èªåã§æäœããã£ã³ã»ã«ããããšã¯ã§ããŸããããæäœããã£ã³ã»ã«ããããã©ããã確èªããããšããã§ããŸããã ããã«ã¯ããŒã«ããããã£ããããŸã ãã£ã³ã»ã«èŠæ±äžã§ã ãšæ¹æ³ ThrowIfCancelRequestedã åŸè ã¯äŸå€ãã¹ããŒããŸã ã¿ã¹ã¯ãã£ã³ã»ã«äŸå€ ãªãŠã è¿ããããŠãã cancelToken ã€ã³ã¹ã¿ã³ã¹ã§ Cancel ã¡ãœãããåŒã³åºãããå Žåã ãããŠããããç§ã䜿çšããããšããå§ãããæ¹æ³ã§ãã ããã¯ãäŸå€æäœãã©ã®æç¹ã§äžæ¢ã§ããããå®å šã«å¶åŸ¡ã§ããããã«ãªãã以åã®ãªãã·ã§ã³ãæ¹åãããã®ã§ãã
ã¹ã¬ãããåæ¢ããããã®æãæ®é ·ãªãªãã·ã§ã³ã¯ãWin32 API TerminateThread é¢æ°ãåŒã³åºãããšã§ãã ãã®é¢æ°ãåŒã³åºããåŸã® CLR ã®åäœã¯äºæž¬ã§ããªãå ŽåããããŸãã MSDN ã§ã¯ããã®é¢æ°ã«ã€ããŠæ¬¡ã®ããã«æžãããŠããŸãã ãTerminateThread ã¯å±éºãªæ©èœã§ãããæã極端ãªå Žåã«ã®ã¿äœ¿çšããå¿ èŠããããŸãã ã
FromAsync ã¡ãœããã䜿çšããŠã¬ã¬ã·ãŒ API ãã¿ã¹ã¯ããŒã¹ã«å€æãã
幞éã«ããã¿ã¹ã¯ãå°å ¥ãããã»ãšãã©ã®éçºè ã«éããªææãåŒãèµ·ããããšããªããªã£ãåŸã«éå§ããããããžã§ã¯ãã«åãçµãããšãã§ããå Žåã¯ããµãŒãããŒãã£è£œã® API ãšèªåã®ããŒã ã® API ã®äž¡æ¹ã«ãå€ãã®å€ã API ãæ±ãå¿ èŠããªããªããŸããéå»ã«æ·åãåããŠããã 幞ããªããšã«ã.NET Framework ããŒã ã¯ç§ãã¡ãäžè©±ããŠãããŸãããããããç®æšã¯èªåãã¡èªèº«ãäžè©±ããããšã§ããã ããã¯ãšãããã.NET ã«ã¯ãå€ãéåæããã°ã©ãã³ã° ã¢ãããŒãã§æžãããã³ãŒããæ°ããéåæããã°ã©ãã³ã° ã¢ãããŒãã«ç°¡åã«å€æããããã®ããŒã«ãå€æ°ãããŸãã ãã® XNUMX ã€ã¯ãTaskFactory ã® FromAsync ã¡ãœããã§ãã 以äžã®ã³ãŒãäŸã§ã¯ããã®ã¡ãœããã䜿çšã㊠WebRequest ã¯ã©ã¹ã®å€ãéåæã¡ãœããã Task ã«ã©ããããŸãã
object state = null;
WebRequest wr = WebRequest.CreateHttp("http://github.com");
await Task.Factory.FromAsync(
wr.BeginGetResponse,
we.EndGetResponse
);
ããã¯åãªãäŸã§ãããçµã¿èŸŒã¿åã§ãããè¡ãå¿ èŠã¯ã»ãšãã©ãããŸããããå€ããããžã§ã¯ãã«ã¯ãIAsyncResult ãè¿ã BeginDoSomething ã¡ãœãããšãããåãåã EndDoSomething ã¡ãœããã溢ããŠããŸãã
TaskCompletionSource ã¯ã©ã¹ã䜿çšããŠã¬ã¬ã·ãŒ API ãã¿ã¹ã¯ããŒã¹ã«å€æãã
èæ ®ãã¹ããã XNUMX ã€ã®éèŠãªããŒã«ã¯ã¯ã©ã¹ã§ãã ã¿ã¹ã¯å®äºãœãŒã¹ã æ©èœãç®çãåäœåçã®ç¹ã§ã¯ãäžã§æžãã ThreadPool ã¯ã©ã¹ã® RegisterWaitForSingleObject ã¡ãœããã圷圿ãšããããããããŸããã ãã®ã¯ã©ã¹ã䜿çšãããšãå€ãéåæ API ãã¿ã¹ã¯ã«ç°¡åãã€äŸ¿å©ã«ã©ããã§ããŸãã
ãããã®ç®çãç®çãšãã TaskFactory ã¯ã©ã¹ã® FromAsync ã¡ãœããã«ã€ããŠã¯ãã§ã«èª¬æãããšæãããã§ãããã ããã§ãMicrosoft ãéå» 15 幎éã«ããã£ãŠæäŸããŠãã .net ã§ã®éåæã¢ãã«ã®éçºã®æŽå²å šäœãæãåºãå¿ èŠããããŸããã¿ã¹ã¯ããŒã¹ã®éåæãã¿ãŒã³ (TAP) ã®åã«ã¯ãéåæããã°ã©ãã³ã° ãã¿ãŒã³ (APP) ããããŸãããã¡ãœããã«ã€ããŠã§ãã å§ããäœããè¿ã IAsyncResult ãšã¡ãœãã çµãããããåãå ¥ãã DoSomething ãšãè¿å¹Žã®éºç£ãšããŠãFromAsync ã¡ãœããã¯ãŸãã«å®ç§ã§ãããæéã®çµéãšãšãã«ãã€ãã³ã ããŒã¹ã®éåæãã¿ãŒã³ã«çœ®ãæããããŸãã (EAP)ãéåææäœãå®äºãããšãã«ã€ãã³ããçºçãããšæ³å®ããŠããŸããã
TaskCompletionSource ã¯ãã€ãã³ã ã¢ãã«ãäžå¿ã«æ§ç¯ãããã¿ã¹ã¯ãšã¬ã¬ã·ãŒ API ãã©ããããã®ã«æé©ã§ãã ãã®åäœã®æ¬è³ªã¯æ¬¡ã®ãšããã§ãããã®ã¯ã©ã¹ã®ãªããžã§ã¯ãã«ã¯ Task åã®ãããªã㯠ããããã£ãããããã®ç¶æ 㯠TaskCompletionSource ã¯ã©ã¹ã® SetResultãSetException ãªã©ã®ã¡ãœãããéããŠå¶åŸ¡ã§ããŸãã await ãªãã¬ãŒã¿ãŒããã®ã¿ã¹ã¯ã«é©çšãããå Žæã§ã¯ãTaskCompletionSource ã«é©çšãããã¡ãœããã«å¿ããŠãã¿ã¹ã¯ãå®è¡ãããããäŸå€ãçºçããŠå€±æããŸãã ãŸã æ確ã§ãªãå Žåã¯ããã®ã³ãŒãäŸãèŠãŠã¿ãŸããããããã§ã¯ãå€ã EAP API ã TaskCompletionSource ã䜿çšããŠã¿ã¹ã¯ã«ã©ãããããŠããŸããã€ãã³ããçºçãããšãã¿ã¹ã¯ã¯ Completed ç¶æ ã«è»¢éãããawait ãªãã¬ãŒã¿ãŒãé©çšããã¡ãœããã瀺ãããŸãããã®ã¿ã¹ã¯ã¯ãªããžã§ã¯ããåä¿¡ãããšå®è¡ãåéããŸã çµæ.
public static Task<Result> DoAsync(this SomeApiInstance someApiObj) {
var completionSource = new TaskCompletionSource<Result>();
someApiObj.Done +=
result => completionSource.SetResult(result);
someApiObj.Do();
result completionSource.Task;
}
TaskCompletionSource ã®ãã³ããšã³ã
TaskCompletionSource ã䜿çšããŠå®è¡ã§ããã®ã¯ãå€ã API ãã©ããããããšã ãã§ã¯ãããŸããã ãã®ã¯ã©ã¹ã䜿çšãããšãã¹ã¬ãããå æããªãã¿ã¹ã¯ã§ããŸããŸãª API ãèšèšã§ããèå³æ·±ãå¯èœæ§ãéãããŸãã ãããŠãç§ãã¡ãèŠããŠããããã«ãã¹ããªãŒã ã¯é«äŸ¡ãªãªãœãŒã¹ã§ããããã®æ°ã¯ïŒäž»ã« RAM ã®éã«ãã£ãŠïŒå¶éãããŠããŸãã ãã®å¶éã¯ãããšãã°ãè€éãªããžãã¹ ããžãã¯ãåããããŒãããã Web ã¢ããªã±ãŒã·ã§ã³ãéçºããããšã§ç°¡åã«éæã§ããŸãã ãã³ã°ããŒãªã³ã°ã®ãããªããªãã¯ãå®è£ ããå Žåã«ç§ã話ããŠããå¯èœæ§ã«ã€ããŠèããŠã¿ãŸãããã
ã€ãŸãããã®ããªãã¯ã®æ¬è³ªã¯æ¬¡ã®ãšããã§ããAPI åŽã§çºçããããã€ãã®ã€ãã³ãã«é¢ããæ å ±ã API ããåãåãå¿ èŠããããŸãããAPI ã¯äœããã®çç±ã§ã€ãã³ããå ±åã§ãããç¶æ ãè¿ãããšããã§ããŸããã ãããã®äŸãšããŠã¯ãWebSocket ã®æ代以åããŸãã¯äœããã®çç±ã§ãã®ãã¯ãããžã䜿çšã§ããªãã£ãæ代ã«ãHTTP äžã«æ§ç¯ããããã¹ãŠã® API ããããŸãã ã¯ã©ã€ã¢ã³ã㯠HTTP ãµãŒããŒã«åãåãããããšãã§ããŸãã HTTP ãµãŒããŒèªäœã¯ã¯ã©ã€ã¢ã³ããšã®éä¿¡ãéå§ã§ããŸããã ç°¡åãªè§£æ±ºçã¯ãã¿ã€ããŒã䜿çšããŠãµãŒããŒãããŒãªã³ã°ããããšã§ãããããã«ãããµãŒããŒã«è¿œå ã®è² è·ãçºçããå¹³å TimerInterval / 2 ã§è¿œå ã®é 延ãçºçããŸãããããåé¿ããããã«ããã³ã° ããŒãªã³ã°ãšåŒã°ããããªãã¯ãçºæãããŸãããã¿ã€ã ã¢ãŠããçµéãããã€ãã³ããçºçãããŸã§ãµãŒããŒã¯åæ¢ããŸããã ã€ãã³ããçºçããå Žåã¯åŠçãããçºçããŠããªãå Žåã¯ãªã¯ãšã¹ããå床éä¿¡ãããŸãã
while(!eventOccures && !timeoutExceeded) {
CheckTimout();
CheckEvent();
Thread.Sleep(1);
}
ãããããã®ãããªãœãªã¥ãŒã·ã§ã³ã¯ãã€ãã³ããåŸ ã£ãŠããã¯ã©ã€ã¢ã³ãã®æ°ãå¢ãããšããã«ã²ã©ããã®ã«ãªãããšãããããŸãã ãã®ãããªåã¯ã©ã€ã¢ã³ãã¯ãã€ãã³ããåŸ æ©ããã¹ã¬ããå šäœãå æããŸãã ã¯ããã€ãã³ããããªã¬ãŒããããšããã« 1ms ã®é 延ãçºçããŸããã»ãšãã©ã®å Žåãããã¯é倧ã§ã¯ãããŸãããããœãããŠã§ã¢ãå¿ èŠä»¥äžã«æªåãããã®ã¯ãªãã§ãããã? Thread.Sleep(1) ãåé€ãããšã100 ã€ã®ããã»ããµ ã³ã¢ã XNUMX% ã¢ã€ãã«ç¶æ ã§ããŒããããç¡é§ãªãµã€ã¯ã«ã§å転ããããšã«ãªããŸãã TaskCompletionSource ã䜿çšãããšããã®ã³ãŒããç°¡åã«äœãçŽããäžèšã§ç¹å®ããããã¹ãŠã®åé¡ã解決ã§ããŸãã
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);
}
}
ãã®ã³ãŒãã¯æ¬çªç°å¢ã«å¯Ÿå¿ãããã®ã§ã¯ãªããåãªããã¢ã§ãã å®éã®ã±ãŒã¹ã§äœ¿çšããã«ã¯ãå°ãªããšãã誰ãäºæããŠããªãæéã«ã¡ãã»ãŒãžãå°çãããšãã®ç¶æ³ã«å¯ŸåŠããå¿ èŠããããŸãããã®å ŽåãAsseptMessageAsync ã¡ãœããã¯ãã§ã«å®äºããã¿ã¹ã¯ãè¿ãå¿ èŠããããŸãã ãããæãäžè¬çãªã±ãŒã¹ã§ããå Žåã¯ãValueTask ã®äœ¿çšãæ€èšã§ããŸãã
ã¡ãã»ãŒãžã®ãªã¯ãšã¹ããåä¿¡ãããšãTaskCompletionSource ãäœæããŠãã£ã¯ã·ã§ããªã«é 眮ããæåã«äœãèµ·ããããã€ãŸãæå®ãããæéãçµéããããã¡ãã»ãŒãžãåä¿¡ãããããåŸ ã¡ãŸãã
ValueTask: ãã®çç±ãšæ¹æ³
async/await æŒç®åã¯ãyield return æŒç®åãšåæ§ã«ãã¡ãœããããã¹ããŒã ãã·ã³ãçæããŸããããã¯æ°ãããªããžã§ã¯ãã®äœæã§ãããã»ãšãã©ã®å ŽåéèŠã§ã¯ãããŸãããããŸãã«åé¡ãçºçããå¯èœæ§ããããŸãã ãã®ã±ãŒã¹ã¯éåžžã«é »ç¹ã«åŒã³åºãããã¡ãœããã§ããå¯èœæ§ããããXNUMX ç§ãããæ°äžãæ°åäžã®åŒã³åºããè¡ãããããšã«ãªããŸãã ã»ãšãã©ã®å Žåããã¹ãŠã® await ã¡ãœããããã€ãã¹ããŠçµæãè¿ããããªã¡ãœãããèšè¿°ãããŠããå Žåã.NET ã¯ãããæé©åããããŒã«ã§ãã ValueTask æ§é ãæäŸããŸãã ãããæ確ã«ããããã«ããã®äœ¿çšäŸãèŠãŠã¿ãŸããããéåžžã«é »ç¹ã«ã¢ã¯ã»ã¹ãããã£ãã·ã¥ããããŸãã ããã€ãã®å€ãå«ãŸããŠããå Žåã¯ãããããè¿ãã ãã§ãããããã§ãªãå Žåã¯ãäœé IO ãå®è¡ããŠå€ãååŸããŸãã åŸè ãéåæã§å®è¡ãããã®ã§ãããããã¯ã¡ãœããå šäœãéåæã«ãªãããšãæå³ããŸãã ãããã£ãŠãã¡ãœãããèšè¿°ããæçœãªæ¹æ³ã¯æ¬¡ã®ããã«ãªããŸãã
public async Task<string> GetById(int id) {
if (cache.TryGetValue(id, out string val))
return val;
return await RequestById(id);
}
å°ãæé©åããããšããèŠæãšããã®ã³ãŒãã®ã³ã³ãã€ã«æã« Roslyn ãäœãçæããããšããè¥å¹²ã®æžå¿µãããããããã®äŸã次ã®ããã«æžãæããããšãã§ããŸãã
public Task<string> GetById(int id) {
if (cache.TryGetValue(id, out string val))
return Task.FromResult(val);
return RequestById(id);
}
å®éããã®å Žåã®æé©ãªè§£æ±ºçã¯ãããããã¹ãæé©åããããšãã€ãŸããäžå¿ èŠãªå²ãåœãŠã GC ãžã®è² è·ãäžããã«ãã£ã¯ã·ã§ããªããå€ãååŸããããšã§ãããããã§ãããŒã¿ãååŸããããã« IO ã«ã¢ã¯ã»ã¹ããå¿ èŠããããŸããªã±ãŒã¹ã§ã¯ã ããã¹ãŠãå€ãæ¹æ³ã®ãŸãŸãã©ã¹/ãã€ãã¹ã®ãŸãŸã«ãªããŸãã
public ValueTask<string> GetById(int id) {
if (cache.TryGetValue(id, out string val))
return new ValueTask<string>(val);
return new ValueTask<string>(RequestById(id));
}
ãã®ã³ãŒãéšåã詳ããèŠãŠã¿ãŸãããããã£ãã·ã¥ã«å€ãããå Žåã¯æ§é äœãäœæããŸãããã以å€ã®å Žåãå®éã®ã¿ã¹ã¯ã¯æå³ã®ããã¿ã¹ã¯ã§ã©ãããããŸãã åŒã³åºãå ã®ã³ãŒãã¯ããã®ã³ãŒããã©ã®ãã¹ã§å®è¡ããããã¯é¢ä¿ãããŸãããC# æ§æã®èŠ³ç¹ããèŠããšããã®å ŽåãValueTask ã¯éåžžã® Task ãšåãããã«åäœããŸãã
TaskScheduler: ã¿ã¹ã¯èµ·åæŠç¥ã®ç®¡ç
次ã«æ€èšããã API ã¯ã¯ã©ã¹ã§ãã ã¿ã¹ã¯ã¹ã±ãžã¥ãŒã© ããã³ãã®æŽŸçåã TPL ã«ã¯ã¹ã¬ããéã§ã¿ã¹ã¯ãåæ£ããããã®æŠç¥ã管çããæ©èœãããããšã¯ãã§ã«äžã§è¿°ã¹ãŸããã ãã®ãããªæŠç¥ã¯ãTaskScheduler ã¯ã©ã¹ã®åå«ã§å®çŸ©ãããŸãã å¿ èŠãªæŠç¥ã¯ã»ãšãã©ãã¹ãŠã©ã€ãã©ãªã§èŠã€ããããšãã§ããŸãã ParallelExtensionsExtrasãMicrosoft ã«ãã£ãŠéçºãããŸãããã.NET ã®äžéšã§ã¯ãªããNuget ããã±ãŒãžãšããŠæäŸãããŸãã ãããã®ããã€ããç°¡åã«èŠãŠã¿ãŸãããã
- çŸåšã®ã¹ã¬ããã¿ã¹ã¯ã¹ã±ãžã¥ãŒã© â çŸåšã®ã¹ã¬ããã§ã¿ã¹ã¯ãå®è¡ããŸã
- LimitedConcurrencyLevelTaskââScheduler â ã³ã³ã¹ãã©ã¯ã¿ãŒã§åãå ¥ãããããã©ã¡ãŒã¿ãŒ N ã«ãã£ãŠåæã«å®è¡ãããã¿ã¹ã¯ã®æ°ãå¶éããŸãã
- OrderedTaskScheduler â LimitedConcurrencyLevelTaskââScheduler(1) ãšããŠå®çŸ©ãããŠãããããã¿ã¹ã¯ã¯é çªã«å®è¡ãããŸãã
- ä»äºçãã¿ã¹ã¯ã¹ã±ãžã¥ãŒã© - å®è£
ããŸã
ä»äºãçã ã¿ã¹ã¯åæ£ãžã®ã¢ãããŒãã åºæ¬çã«ãããã¯å¥åã® ThreadPool ã§ãã .NET ã§ã¯ ThreadPool ããã¹ãŠã®ã¢ããªã±ãŒã·ã§ã³ã«å¯Ÿå¿ããéçã¯ã©ã¹ã§ãããšããåé¡ã解決ããŸããã€ãŸããããã°ã©ã ã®äžéšã§ãã®ãªãŒããŒããŒãã誀ã£ã䜿çšãå¥ã®éšåã§å¯äœçšãåŒãèµ·ããå¯èœæ§ããããŸãã ããã«ããã®ãããªæ¬ é¥ã®åå ãç解ããããšã¯éåžžã«å°é£ã§ãã ããã ThreadPool ã®äœ¿çšãç©æ¥µçã§äºæž¬äžå¯èœãªããã°ã©ã ã®äžéšã§ã¯ãå¥åã® WorkStealingTaskScheduler ã䜿çšããå¿ èŠãããå ŽåããããŸãã - ãã¥ãŒã«ç»é²ãããã¿ã¹ã¯ã¹ã±ãžã¥ãŒã© â åªå ãã¥ãŒã®ã«ãŒã«ã«åŸã£ãŠã¿ã¹ã¯ãå®è¡ã§ããŸãã
- ã¿ã¹ã¯ããšã®ã¹ã¬ããã¹ã±ãžã¥ãŒã© â å®è¡ãããã¿ã¹ã¯ããšã«åå¥ã®ã¹ã¬ãããäœæããŸãã å®äºãŸã§ã«äºæ³å€ã«é·ãæéããããã¿ã¹ã¯ã«åœ¹ç«ã¡ãŸãã
è¯ã詳现ããããŸã
ã¿ã¹ã¯ã«é¢é£ãããããããã®ãç°¡åã«ãããã°ã§ããããã«ãVisual Studio ã«ã¯ã¿ã¹ã¯ ãŠã£ã³ããŠããããŸãã ãã®ãŠã£ã³ããŠã§ã¯ãã¿ã¹ã¯ã®çŸåšã®ç¶æ ã確èªããçŸåšå®è¡äžã®ã³ãŒãè¡ã«ãžã£ã³ãã§ããŸãã
PLinq ãš Parallel ã¯ã©ã¹
ã¿ã¹ã¯ãšããã«ã€ããŠè¿°ã¹ããã¹ãŠã«å ããŠã.NET ã«ã¯ããã« 2 ã€ã®èå³æ·±ãããŒã«ããããŸããPLinq (LinqXNUMXParallel) ãš Parallel ã¯ã©ã¹ã§ãã XNUMX ã€ç®ã¯ããã¹ãŠã® Linq æäœãè€æ°ã®ã¹ã¬ããã§äžŠåå®è¡ããããšãçŽæããŸãã ã¹ã¬ããã®æ°ã¯ãWithDegreeOfParallelism æ¡åŒµã¡ãœããã䜿çšããŠæ§æã§ããŸãã æ®å¿µãªãããã»ãšãã©ã®å Žåãããã©ã«ã ã¢ãŒãã® PLinq ã«ã¯ãé床ã倧å¹
ã«åäžãããã»ã©ã®ããŒã¿ ãœãŒã¹ã®å
éšã«é¢ããååãªæ
å ±ããããŸããããã®äžæ¹ã§ãè©Šè¡ã³ã¹ãã¯éåžžã«äœããªããŸããäºåã« AsParallel ã¡ãœãããåŒã³åºãã ãã§ååã§ãã Linq ã¡ãœããã®ãã§ãŒã³ã確èªããããã©ãŒãã³ã¹ ãã¹ããå®è¡ããŸãã ããã«ãããŒãã£ã·ã§ã³ ã¡ã«ããºã ã䜿çšããŠãããŒã¿ ãœãŒã¹ã®æ§è³ªã«é¢ããè¿œå æ
å ±ã PLinq ã«æž¡ãããšãã§ããŸãã ãã£ãšèªãããšãã§ããŸã
Parallel éçã¯ã©ã¹ã¯ãForeach ã³ã¬ã¯ã·ã§ã³ã䞊åã§å埩åŠçããFor ã«ãŒããå®è¡ããè€æ°ã®ããªã²ãŒãã䞊å Invoke å®è¡ããããã®ã¡ãœãããæäŸããŸãã çŸåšã®ã¹ã¬ããã®å®è¡ã¯ãèšç®ãå®äºãããŸã§åæ¢ãããŸãã ã¹ã¬ããã®æ°ã¯ãæåŸã®åŒæ°ãšã㊠ParallelOptions ãæž¡ãããšã«ãã£ãŠæ§æã§ããŸãã ãªãã·ã§ã³ã䜿çšã㊠TaskScheduler ãš CancelToken ãæå®ããããšãã§ããŸãã
æèŠ
ã¬ããŒãã®è³æãšãã®åŸã®ä»äºäžã«åéããæ å ±ã«åºã¥ããŠãã®èšäºãæžãå§ãããšããããã»ã©å€ãã®æ å ±ããããšã¯äºæ³ããŠããŸããã§ããã ããŠããã®èšäºãå ¥åããŠããããã¹ã ãšãã£ã¿ã 15 ããŒãžãçµãã£ããšéé£ãããã«åããŠããããäžéçµæãèŠçŽããŸãã ä»ã®ããªãã¯ãAPIãããžã¥ã¢ã« ããŒã«ãèœãšãç©Žã«ã€ããŠã¯ã次ã®èšäºã§èª¬æããŸãã
çµè«ïŒ
- ææ°ã® PC ã®ãªãœãŒã¹ã䜿çšããã«ã¯ãã¹ã¬ãããéåæã䞊ååŠçãæäœããããã®ããŒã«ãç¥ãå¿ èŠããããŸãã
- .NET ã«ã¯ãããã®ç®çã®ããã®ããŸããŸãªããŒã«ãå€æ°ãããŸã
- ãã¹ãŠãäžåºŠã«ç»å Žããããã§ã¯ãªããããå€ã API ãèŠã€ããããšããããããŸãããæéããããã«å€ã API ãå€æããæ¹æ³ããããŸãã
- .NET ã§ã®ã¹ã¬ããã®æäœã¯ãThread ã¯ã©ã¹ãš ThreadPool ã¯ã©ã¹ã«ãã£ãŠè¡šãããŸãã
- Thread.AbortãThread.Interruptãããã³ Win32 API ã® TerminateThread ã¡ãœããã¯å±éºã§ããããã䜿çšã¯ãå§ãã§ããŸããã 代ããã«ãCancelToken ã¡ã«ããºã ã䜿çšããããšããå§ãããŸãã
- æµãã¯è²Žéãªè³æºã§ããããã®äŸçµŠã«ã¯éãããããŸãã ã¹ã¬ãããã€ãã³ãã®åŸ æ©ã§ããžãŒç¶æ ã«ãªãç¶æ³ã¯é¿ããŠãã ããã ãã®ããã«ã¯ãTaskCompletionSource ã¯ã©ã¹ã䜿çšãããšäŸ¿å©ã§ãã
- 䞊ååŠçãšéåæåŠçãè¡ãããã®æã匷åãã€é«åºŠãª .NET ããŒã«ã¯ãã¿ã¹ã¯ã§ãã
- C# ã® async/await æŒç®åã¯ããã³ããããã³ã°åŸ æ©ã®æŠå¿µãå®è£ ããŸãã
- TaskScheduler 掟çã¯ã©ã¹ã䜿çšããŠãã¹ã¬ããéã§ã®ã¿ã¹ã¯ã®åæ£ãå¶åŸ¡ã§ããŸãã
- ValueTask æ§é ã¯ãããã ãã¹ãšã¡ã¢ãª ãã©ãã£ãã¯ã®æé©åã«åœ¹ç«ã¡ãŸãã
- Visual Studio ã® [ã¿ã¹ã¯] ãŠã£ã³ããŠãš [ã¹ã¬ãã] ãŠã£ã³ããŠã«ã¯ããã«ãã¹ã¬ãã ã³ãŒããŸãã¯éåæã³ãŒãã®ãããã°ã«åœ¹ç«ã€å€ãã®æ å ±ãæäŸãããŸãã
- PLinq ã¯åªããããŒã«ã§ãããããŒã¿ ãœãŒã¹ã«é¢ããååãªæ å ±ãå«ãŸããŠããªãå¯èœæ§ããããŸãããããã¯ããŒãã£ã·ã§ãã³ã° ã¡ã«ããºã ã䜿çšããŠä¿®æ£ã§ããŸãã
- ç¶ç¶ããã«ã¯...
åºæïŒ habr.com