.NET: மல்டித்ரெடிங் மற்றும் அசின்க்ரோனியுடன் வேலை செய்வதற்கான கருவிகள். பகுதி 1

ஹப்ரின் அசல் கட்டுரையை நான் வெளியிடுகிறேன், அதன் மொழிபெயர்ப்பு நிறுவனத்தில் வெளியிடப்பட்டுள்ளது வலைப்பதிவு இடுகை.

இங்கே மற்றும் இப்போது முடிவுக்காக காத்திருக்காமல், ஒத்திசைவற்ற முறையில் ஏதாவது செய்ய வேண்டிய அவசியம் அல்லது அதைச் செய்யும் பல அலகுகளுக்கு இடையில் பெரிய வேலையைப் பிரிப்பது, கணினிகளின் வருகைக்கு முன்பே இருந்தது. அவர்களின் வருகையுடன், இந்த தேவை மிகவும் உறுதியானது. இப்போது, ​​2019 ஆம் ஆண்டில், நான் இந்த கட்டுரையை 8-கோர் இன்டெல் கோர் செயலி கொண்ட மடிக்கணினியில் தட்டச்சு செய்கிறேன், அதில் நூற்றுக்கும் மேற்பட்ட செயல்முறைகள் இணையாக இயங்குகின்றன, மேலும் அதிக நூல்கள் உள்ளன. அருகிலேயே, சில ஆண்டுகளுக்கு முன்பு வாங்கப்பட்ட, சற்றே பழுதடைந்த போன் உள்ளது, அதில் 8-கோர் செயலி உள்ளது. கருப்பொருள் ஆதாரங்கள் கட்டுரைகள் மற்றும் வீடியோக்களால் நிரம்பியுள்ளன, அங்கு 16-கோர் செயலிகளைக் கொண்ட இந்த ஆண்டின் முதன்மை ஸ்மார்ட்போன்களை அவற்றின் ஆசிரியர்கள் பாராட்டுகிறார்கள். MS Azure 20 கோர் செயலி மற்றும் 128 TB ரேம் கொண்ட மெய்நிகர் இயந்திரத்தை $2/மணிக்கு குறைவாக வழங்குகிறது. துரதிருஷ்டவசமாக, அதிகபட்சமாக பிரித்தெடுக்க முடியாது மற்றும் நூல்களின் தொடர்புகளை நிர்வகிக்க முடியாமல் இந்த சக்தியைப் பயன்படுத்த முடியாது.

சொல்லியல்

செயல்முறை - OS பொருள், தனிமைப்படுத்தப்பட்ட முகவரி இடம், நூல்கள் உள்ளன.
நூல் - ஒரு OS ஆப்ஜெக்ட், செயல்பாட்டின் மிகச்சிறிய அலகு, ஒரு செயல்முறையின் ஒரு பகுதி, ஒரு செயல்முறைக்குள் த்ரெட்கள் நினைவகம் மற்றும் பிற வளங்களை தங்களுக்குள் பகிர்ந்து கொள்கின்றன.
பல்பணி - OS சொத்து, ஒரே நேரத்தில் பல செயல்முறைகளை இயக்கும் திறன்
மல்டி-கோர் - செயலியின் சொத்து, தரவு செயலாக்கத்திற்கு பல கோர்களைப் பயன்படுத்தும் திறன்
பல செயலாக்கம் - ஒரு கணினியின் சொத்து, உடல் ரீதியாக பல செயலிகளுடன் ஒரே நேரத்தில் வேலை செய்யும் திறன்
மல்டித்ரெடிங் - ஒரு செயல்முறையின் ஒரு பண்பு, தரவு செயலாக்கத்தை பல நூல்களில் விநியோகிக்கும் திறன்.
பேரலலிசம் - ஒரு யூனிட் நேரத்திற்கு ஒரே நேரத்தில் உடல் ரீதியாக பல செயல்களைச் செய்தல்
ஒத்திசைவு - இந்த செயலாக்கம் முடிவடையும் வரை காத்திருக்காமல் ஒரு செயல்பாட்டைச் செயல்படுத்துதல்; மரணதண்டனையின் முடிவை பின்னர் செயல்படுத்தலாம்.

உருவகம்

எல்லா வரையறைகளும் நன்றாக இல்லை மற்றும் சிலவற்றிற்கு கூடுதல் விளக்கம் தேவை, எனவே முறையாக அறிமுகப்படுத்தப்பட்ட சொற்களில் காலை உணவை சமைப்பது பற்றிய ஒரு உருவகத்தை நான் சேர்க்கிறேன். இந்த உருவகத்தில் காலை உணவை சமைப்பது ஒரு செயல்முறை.

காலை உணவு தயாரிக்கும் போது நான் (சிபியுநான் சமையலறைக்கு வருகிறேன் (கணினி) எனக்கு 2 கைகள் உள்ளன (நிறங்கள்) சமையலறையில் பல சாதனங்கள் உள்ளன (IO): அடுப்பு, கெட்டில், டோஸ்டர், குளிர்சாதன பெட்டி. நான் வாயுவை இயக்கி, அதன் மீது ஒரு வாணலியை வைத்து, அது சூடாக்கும் வரை காத்திருக்காமல் எண்ணெயை ஊற்றுகிறேன் (ஒத்திசைவற்ற முறையில், தடையற்ற-IO-காத்திருப்பு), நான் குளிர்சாதன பெட்டியில் இருந்து முட்டைகளை எடுத்து ஒரு தட்டில் உடைத்து, ஒரு கையால் அடிக்கிறேன் (நூல்#1), மற்றும் இரண்டாவது (நூல்#2) தட்டைப் பிடித்தல் (பகிரப்பட்ட வளம்). இப்போது நான் கெட்டியை இயக்க விரும்புகிறேன், ஆனால் என்னிடம் போதுமான கைகள் இல்லை (நூல் பட்டினி) இந்த நேரத்தில், வறுக்கப்படுகிறது பான் வெப்பமடைகிறது (முடிவை செயலாக்குகிறது) அதில் நான் தட்டிவிட்டதை ஊற்றுகிறேன். நான் கெட்டிலை அடைந்து அதை இயக்கி அதில் தண்ணீர் கொதிப்பதை முட்டாள்தனமாக பார்க்கிறேன் (பிளாக்கிங்-ஐஓ-காத்திருப்பு), இந்த நேரத்தில் அவர் ஆம்லெட்டை அடித்த தட்டை அவர் கழுவியிருக்கலாம்.

2 கைகளை மட்டுமே பயன்படுத்தி ஆம்லெட் சமைத்தேன், இன்னும் என்னிடம் இல்லை, ஆனால் அதே நேரத்தில், ஆம்லெட்டை அடிக்கும் தருணத்தில், ஒரே நேரத்தில் 3 செயல்பாடுகள் நடந்தன: ஆம்லெட்டை அடிப்பது, தட்டைப் பிடிப்பது, வாணலியை சூடாக்குவது. CPU என்பது கணினியின் வேகமான பகுதியாகும், IO என்பது பெரும்பாலும் எல்லாம் குறைகிறது, எனவே பெரும்பாலும் IO இலிருந்து தரவைப் பெறும்போது CPU ஐ ஆக்கிரமிப்பதே சிறந்த தீர்வாகும்.

உருவகத்தைத் தொடர்கிறேன்:

  • ஆம்லெட் தயாரிக்கும் பணியில், நான் ஆடைகளை மாற்ற முயற்சிப்பேன் என்றால், இது பல்பணிக்கு ஒரு எடுத்துக்காட்டு. ஒரு முக்கியமான நுணுக்கம்: மக்களை விட கணினிகள் இதில் சிறந்தவை.
  • பல சமையல்காரர்களுடன் ஒரு சமையலறை, உதாரணமாக ஒரு உணவகத்தில் - ஒரு மல்டி-கோர் கணினி.
  • ஒரு ஷாப்பிங் சென்டரில் உணவு நீதிமன்றத்தில் பல உணவகங்கள் - தரவு மையம்

.NET கருவிகள்

.NET பல விஷயங்களைப் போலவே நூல்களிலும் வேலை செய்வதில் சிறந்தது. ஒவ்வொரு புதிய பதிப்பிலும், அவர்களுடன் பணிபுரிய மேலும் மேலும் புதிய கருவிகளை அறிமுகப்படுத்துகிறது, OS த்ரெட்களில் சுருக்கத்தின் புதிய அடுக்குகள். சுருக்கங்களின் கட்டுமானத்துடன் பணிபுரியும் போது, ​​கட்டமைப்பை உருவாக்குபவர்கள் ஒரு அணுகுமுறையைப் பயன்படுத்துகின்றனர், இது ஒரு உயர்-நிலை சுருக்கத்தைப் பயன்படுத்தும் போது, ​​கீழே ஒன்று அல்லது அதற்கு மேற்பட்ட நிலைகளைக் குறைக்கும். பெரும்பாலும் இது அவசியமில்லை, உண்மையில் இது ஒரு துப்பாக்கியால் உங்களை காலில் சுடுவதற்கான கதவைத் திறக்கிறது, ஆனால் சில நேரங்களில், அரிதான சந்தர்ப்பங்களில், தற்போதைய சுருக்கத்தின் மட்டத்தில் தீர்க்கப்படாத சிக்கலைத் தீர்ப்பதற்கான ஒரே வழி இதுவாக இருக்கலாம். .

கருவிகள் மூலம், கட்டமைப்பு மற்றும் மூன்றாம் தரப்பு தொகுப்புகள் மூலம் வழங்கப்படும் பயன்பாட்டு நிரலாக்க இடைமுகங்கள் (APIகள்) மற்றும் பல-திரிக்கப்பட்ட குறியீடு தொடர்பான ஏதேனும் சிக்கல்களுக்கான தேடலை எளிதாக்கும் முழு மென்பொருள் தீர்வுகளையும் குறிக்கிறேன்.

ஒரு இழையைத் தொடங்குதல்

த்ரெட் கிளாஸ் என்பது .நெட்டில் த்ரெட்களுடன் வேலை செய்வதற்கான அடிப்படை வகுப்பாகும். கட்டமைப்பாளர் இரண்டு பிரதிநிதிகளில் ஒன்றை ஏற்றுக்கொள்கிறார்:

  • ThreadStart - அளவுருக்கள் இல்லை
  • ParametrizedThreadStart - வகை பொருளின் ஒரு அளவுருவுடன்.

தொடக்க முறையை அழைத்த பிறகு புதிதாக உருவாக்கப்பட்ட திரியில் பிரதிநிதி செயல்படுத்தப்படும். ParametrizedThreadStart வகையின் ஒரு பிரதிநிதியை கன்ஸ்ட்ரக்டருக்கு அனுப்பியிருந்தால், தொடக்க முறைக்கு ஒரு பொருளை அனுப்ப வேண்டும். எந்தவொரு உள்ளூர் தகவலையும் ஸ்ட்ரீமுக்கு மாற்ற இந்த வழிமுறை தேவை. ஒரு நூலை உருவாக்குவது ஒரு விலையுயர்ந்த செயலாகும், மேலும் நூல் ஒரு கனமான பொருளாகும், ஏனெனில் இது ஸ்டேக்கில் 1MB நினைவகத்தை ஒதுக்குகிறது மற்றும் OS API உடன் தொடர்பு தேவைப்படுகிறது.

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

ThreadPool வகுப்பு ஒரு குளத்தின் கருத்தை குறிக்கிறது. .NET இல், த்ரெட் பூல் என்பது பொறியியலின் ஒரு பகுதியாகும், மேலும் மைக்ரோசாப்ட் டெவலப்பர்கள் பலவிதமான சூழ்நிலைகளில் இது சிறந்த முறையில் செயல்படுவதை உறுதிசெய்ய நிறைய முயற்சிகளை மேற்கொண்டுள்ளனர்.

பொதுவான கருத்து:

பயன்பாடு தொடங்கும் தருணத்திலிருந்து, இது பின்னணியில் இருப்பு உள்ள பல நூல்களை உருவாக்குகிறது மற்றும் அவற்றைப் பயன்படுத்துவதற்கான திறனை வழங்குகிறது. நூல்கள் அடிக்கடி மற்றும் அதிக எண்ணிக்கையில் பயன்படுத்தப்பட்டால், அழைப்பாளரின் தேவைகளைப் பூர்த்தி செய்ய குளம் விரிவடைகிறது. சரியான நேரத்தில் குளத்தில் இலவச இழைகள் இல்லாத போது, ​​அது ஒன்று திரும்பும் வரை காத்திருக்கும் அல்லது புதிய ஒன்றை உருவாக்கும். சில குறுகிய கால செயல்களுக்கு த்ரெட் பூல் சிறந்தது மற்றும் பயன்பாட்டின் முழு செயல்பாடு முழுவதும் சேவைகளாக இயங்கும் செயல்பாடுகளுக்கு மிகவும் பொருத்தமானது அல்ல.

பூலில் இருந்து ஒரு நூலைப் பயன்படுத்த, ஒரு QueueUserWorkItem முறை உள்ளது, இது WaitCallback வகையின் பிரதிநிதியை ஏற்றுக்கொள்கிறது, இது ParametrizedThreadStart போன்ற அதே கையொப்பத்தைக் கொண்டுள்ளது, மேலும் அதற்கு அனுப்பப்பட்ட அளவுரு அதே செயல்பாட்டைச் செய்கிறது.

ThreadPool.QueueUserWorkItem(...);

குறைவாக அறியப்பட்ட நூல் பூல் முறை RegisterWaitForSingleObject ஐ தடை செய்யாத IO செயல்பாடுகளை ஒழுங்கமைக்கப் பயன்படுகிறது. இந்த முறைக்கு அனுப்பப்பட்ட பிரதிநிதி, WaitHandle முறைக்கு அனுப்பப்பட்டதும் "வெளியிடப்பட்டது" என்று அழைக்கப்படும்.

ThreadPool.RegisterWaitForSingleObject(...)

.NET ஒரு த்ரெட் டைமரைக் கொண்டுள்ளது மற்றும் இது WinForms/WPF டைமர்களில் இருந்து வேறுபடுகிறது, அதன் கையாளுபவர் குளத்தில் இருந்து எடுக்கப்பட்ட ஒரு நூலில் அழைக்கப்படுவார்.

System.Threading.Timer

பிகின்இன்வோக் முறை - பூலில் இருந்து ஒரு நூலுக்கு மரணதண்டனைக்காக ஒரு பிரதிநிதியை அனுப்ப ஒரு கவர்ச்சியான வழியும் உள்ளது.

DelegateInstance.BeginInvoke

Kernel32.dll Win32 API இலிருந்து CreateThread - மேலே உள்ள பல முறைகளை அழைக்கக்கூடிய செயல்பாட்டைப் பற்றி நான் சுருக்கமாக வாழ விரும்புகிறேன். வெளிப்புற முறைகளின் பொறிமுறைக்கு நன்றி, இந்த செயல்பாட்டை அழைக்க ஒரு வழி உள்ளது. மரபுக் குறியீட்டின் பயங்கரமான உதாரணத்தில் ஒருமுறை மட்டுமே இதுபோன்ற அழைப்பை நான் பார்த்திருக்கிறேன், இதை சரியாகச் செய்த ஆசிரியரின் உந்துதல் இன்னும் எனக்கு ஒரு மர்மமாகவே உள்ளது.

Kernel32.dll CreateThread

நூல்களைப் பார்ப்பது மற்றும் பிழைத்திருத்தம் செய்தல்

உங்களால் உருவாக்கப்பட்ட நூல்கள், அனைத்து மூன்றாம் தரப்பு கூறுகள் மற்றும் .NET பூல் ஆகியவற்றை விஷுவல் ஸ்டுடியோவின் த்ரெட்ஸ் விண்டோவில் பார்க்கலாம். பயன்பாடு பிழைத்திருத்தத்தின் கீழ் மற்றும் பிரேக் பயன்முறையில் இருக்கும்போது மட்டுமே இந்த சாளரம் நூல் தகவலைக் காண்பிக்கும். இங்கே நீங்கள் ஒவ்வொரு தொடரின் ஸ்டாக் பெயர்கள் மற்றும் முன்னுரிமைகளை வசதியாகப் பார்க்கலாம் மற்றும் பிழைத்திருத்தத்தை ஒரு குறிப்பிட்ட தொடருக்கு மாற்றலாம். த்ரெட் வகுப்பின் முன்னுரிமைப் பண்பைப் பயன்படுத்தி, ஒரு நூலின் முன்னுரிமையை நீங்கள் அமைக்கலாம், த்ரெட்களுக்கு இடையில் செயலி நேரத்தைப் பிரிக்கும்போது OC மற்றும் CLR ஆகியவை பரிந்துரையாக உணரும்.

.NET: மல்டித்ரெடிங் மற்றும் அசின்க்ரோனியுடன் வேலை செய்வதற்கான கருவிகள். பகுதி 1

பணி இணை நூலகம்

டாஸ்க் பேரலல் லைப்ரரி (TPL) .NET 4.0 இல் அறிமுகப்படுத்தப்பட்டது. இப்போது இது நிலையானது மற்றும் ஒத்திசைவற்றுடன் பணிபுரியும் முக்கிய கருவியாகும். பழைய அணுகுமுறையைப் பயன்படுத்தும் எந்தக் குறியீடும் மரபு என்று கருதப்படுகிறது. TPL இன் அடிப்படை அலகு System.Threading.Tasks நேம்ஸ்பேஸில் இருந்து பணி வகுப்பு ஆகும். ஒரு பணி என்பது ஒரு நூல் மீது சுருக்கம். C# மொழியின் புதிய பதிப்பின் மூலம், Tasks - async/waiit operators உடன் பணிபுரிவதற்கான நேர்த்தியான வழியைப் பெற்றுள்ளோம். இந்த கருத்துக்கள் ஒத்திசைவற்ற குறியீட்டை எளிமையாகவும் ஒத்திசைவாகவும் எழுதுவதை சாத்தியமாக்கியது, இது நூல்களின் உள் செயல்பாடுகளைப் பற்றி சிறிதும் புரிந்து கொள்ளாதவர்களும் அவற்றைப் பயன்படுத்தும் பயன்பாடுகள், நீண்ட செயல்பாடுகளைச் செய்யும்போது உறைந்து போகாத பயன்பாடுகளை எழுதுவதை இது சாத்தியமாக்கியது. ஒத்திசைவு/காத்திருப்பு என்பது ஒன்று அல்லது பல கட்டுரைகளுக்கான தலைப்பு, ஆனால் அதன் சாராம்சத்தை சில வாக்கியங்களில் பெற முயற்சிப்பேன்:

  • async என்பது பணி அல்லது வெற்றிடத்தைத் திருப்பியளிக்கும் முறையின் மாற்றியமைப்பதாகும்
  • மற்றும் காத்திருப்பு என்பது தடுக்காத டாஸ்க் வெயிட்டிங் ஆபரேட்டர்.

மீண்டும் ஒருமுறை: காத்திருப்பு ஆபரேட்டர், பொது வழக்கில் (விதிவிலக்குகள் உள்ளன), செயல்படுத்தும் தற்போதைய தொடரை மேலும் வெளியிடுவார், மேலும் பணி அதன் செயல்பாட்டை முடித்ததும், மற்றும் நூலை (உண்மையில், சூழலைச் சொல்வது மிகவும் சரியாக இருக்கும். , ஆனால் அதைப் பற்றி மேலும் பின்னர்) மேலும் முறையை தொடர்ந்து செயல்படுத்தும். .NET இன் உள்ளே, இந்த பொறிமுறையானது மகசூல் வருவாயைப் போலவே செயல்படுத்தப்படுகிறது, எழுதப்பட்ட முறை முழு வகுப்பாக மாறும் போது, ​​இது ஒரு மாநில இயந்திரம் மற்றும் இந்த நிலைகளைப் பொறுத்து தனித்தனி துண்டுகளாக செயல்படுத்தப்படலாம். ஆர்வமுள்ள எவரும் asynс/waiit ஐப் பயன்படுத்தி எந்த எளிய குறியீட்டையும் எழுதலாம், தொகுக்கலாம் மற்றும் 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
}

பல விருப்பங்களுடன் ஒரு பணி உருவாக்கப்பட்டது:

  • லாங் ரன்னிங் என்பது பணி விரைவாக முடிக்கப்படாது என்பதற்கான குறிப்பு ஆகும், அதாவது குளத்திலிருந்து ஒரு நூலை எடுக்காமல், மற்றவர்களுக்கு தீங்கு விளைவிக்காதபடி இந்த பணிக்காக தனி ஒன்றை உருவாக்குவது மதிப்புக்குரியதாக இருக்கலாம்.
  • AttachedToParent - பணிகளை ஒரு படிநிலையில் வரிசைப்படுத்தலாம். இந்த விருப்பம் பயன்படுத்தப்பட்டிருந்தால், பணியானது தானே முடிந்து அதன் குழந்தைகளின் மரணதண்டனைக்காக காத்திருக்கும் நிலையில் இருக்கலாம்.
  • PreferFairness - அதாவது, செயல்படுத்துவதற்காக அனுப்பப்பட்ட பணிகளை, பின்னர் அனுப்புவதற்கு முன்பு செயல்படுத்துவது நல்லது. ஆனால் இது ஒரு பரிந்துரை மற்றும் முடிவுகள் உத்தரவாதம் இல்லை.

இந்த முறைக்கு அனுப்பப்பட்ட இரண்டாவது அளவுரு CancellationToken ஆகும். ஒரு செயல்பாட்டைத் தொடங்கிய பிறகு அதை ரத்துசெய்வதைச் சரியாகக் கையாள, செயல்படுத்தப்படும் குறியீட்டில் CancellationToken நிலைக்கான காசோலைகள் நிரப்பப்பட வேண்டும். காசோலைகள் ஏதும் இல்லை என்றால், CancellationTokenSource ஆப்ஜெக்ட்டில் அழைக்கப்படும் ரத்துசெய்யும் முறையானது, அது தொடங்குவதற்கு முன்பு மட்டுமே அதைச் செயல்படுத்துவதை நிறுத்த முடியும்.

கடைசி அளவுரு TaskScheduler வகையின் திட்டமிடல் பொருளாகும். இந்த வகுப்பும் அதன் வழித்தோன்றல்களும் த்ரெட்கள் முழுவதும் பணிகளை விநியோகிப்பதற்கான உத்திகளை நிர்வகிக்க வடிவமைக்கப்பட்டுள்ளது; இயல்பாக, பூலில் இருந்து ஒரு சீரற்ற நூலில் பணி செயல்படுத்தப்படும்.

காத்திருப்பு ஆபரேட்டர் உருவாக்கப்பட்ட பணிக்கு பயன்படுத்தப்படுகிறது, அதாவது அதன் பிறகு எழுதப்பட்ட குறியீடு, ஒன்று இருந்தால், காத்திருப்புக்கு முன் உள்ள குறியீட்டின் அதே சூழலில் (பெரும்பாலும் இது அதே நூலில் அர்த்தம்) செயல்படுத்தப்படும்.

இந்த முறை ஒத்திசைவு வெற்றிடமாகக் குறிக்கப்பட்டுள்ளது, அதாவது இது காத்திருக்கும் ஆபரேட்டரைப் பயன்படுத்தலாம், ஆனால் அழைப்புக் குறியீடு செயல்படுத்தப்படுவதற்கு காத்திருக்க முடியாது. அத்தகைய அம்சம் அவசியமானால், முறையானது பணியைத் திருப்பித் தர வேண்டும். ஒத்திசைவு வெற்றிடத்தைக் குறிக்கும் முறைகள் மிகவும் பொதுவானவை: ஒரு விதியாக, இவை நிகழ்வு கையாளுபவர்கள் அல்லது நெருப்பில் வேலை செய்யும் மற்றும் கொள்கையை மறந்துவிடும் பிற முறைகள். மரணதண்டனை முடிவடையும் வரை காத்திருக்கும் வாய்ப்பை வழங்குவது மட்டுமல்லாமல், முடிவையும் வழங்க வேண்டும் என்றால், நீங்கள் பணியைப் பயன்படுத்த வேண்டும்.

StartNew முறை திரும்பிய பணியிலும், வேறு எந்த முறையிலும், நீங்கள் ConfigureAwait முறையை தவறான அளவுருவுடன் அழைக்கலாம், பின்னர் காத்திருப்புக்குப் பிறகு செயல்படுத்துவது கைப்பற்றப்பட்ட சூழலில் தொடரும், ஆனால் தன்னிச்சையானது. காத்திருப்புக்குப் பிறகு குறியீட்டிற்கு செயல்படுத்தும் சூழல் முக்கியமில்லாதபோது இது எப்போதும் செய்யப்பட வேண்டும். இது நூலகத்தில் தொகுக்கப்பட்ட குறியீட்டை எழுதும் போது 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
}

முதல் எடுத்துக்காட்டில், அழைப்புத் தொடரைத் தடுக்காமல் பணி முடிவடையும் வரை நாங்கள் காத்திருக்கிறோம்; அது ஏற்கனவே இருக்கும் போது மட்டுமே முடிவு செயலாக்கத்திற்குத் திரும்புவோம்; அதுவரை, அழைப்புத் தொடரை அதன் சொந்த சாதனங்களுக்கு விட்டுவிடுவோம்.

இரண்டாவது விருப்பத்தில், முறையின் முடிவு கணக்கிடப்படும் வரை அழைப்பு நூலைத் தடுக்கிறோம். இது மோசமானது, ஏனெனில் நிரலின் மதிப்புமிக்க வளமான ஒரு நூலை நாம் எளிமையான செயலற்ற தன்மையுடன் ஆக்கிரமித்துள்ளோம், ஆனால் நாம் அழைக்கும் முறையின் குறியீடு காத்திருத்தலைக் கொண்டிருந்தால், ஒத்திசைவு சூழலுக்குப் பிறகு அழைப்புத் தொடருக்குத் திரும்ப வேண்டும். காத்திருங்கள், பின்னர் நாம் ஒரு முட்டுக்கட்டைப் பெறுவோம்: ஒத்திசைவற்ற முறையின் முடிவு கணக்கிடப்படும்போது அழைப்புத் தொடரிழை காத்திருக்கிறது, ஒத்திசைவற்ற முறையானது அழைப்புத் தொடரில் அதன் செயல்பாட்டைத் தொடர வீணாக முயற்சிக்கிறது.

இந்த அணுகுமுறையின் மற்றொரு குறைபாடு சிக்கலான பிழை கையாளுதல் ஆகும். உண்மை என்னவென்றால், async/waiit ஐப் பயன்படுத்தும் போது ஒத்திசைவற்ற குறியீட்டில் ஏற்படும் பிழைகளைக் கையாள்வது மிகவும் எளிதானது - அவை குறியீடு ஒத்திசைவாக இருந்தால் அதே போல் செயல்படும். நாம் ஒரு பணிக்கு ஒத்திசைவான காத்திருப்பு பேயோட்டுதலைப் பயன்படுத்தினால், அசல் விதிவிலக்கு மொத்த விலக்காக மாறும், அதாவது. விதிவிலக்கைக் கையாள, நீங்கள் InnerException வகையை ஆய்வு செய்து, ஒரு கேட்ச் பிளாக்கிற்குள் நீங்கள் ஒரு if சங்கிலியை எழுத வேண்டும் அல்லது C# உலகில் மிகவும் பரிச்சயமான கேட்ச் பிளாக்குகளின் சங்கிலிக்குப் பதிலாக, கட்டும் போது கேட்ச்சைப் பயன்படுத்த வேண்டும்.

மூன்றாவது மற்றும் இறுதி எடுத்துக்காட்டுகள் அதே காரணத்திற்காக மோசமாகக் குறிக்கப்பட்டுள்ளன மற்றும் ஒரே மாதிரியான சிக்கல்களைக் கொண்டிருக்கின்றன.

எப்பொழுது மற்றும் எப்பொழுது அனைத்து முறைகளும் பணிகளின் குழுவைக் காத்திருப்பதற்கு மிகவும் வசதியானவை; அவை பணிகளின் ஒரு குழுவை ஒன்றாக இணைக்கின்றன, இது குழுவிலிருந்து ஒரு பணியை முதலில் தூண்டும் போது அல்லது அவை அனைத்தும் செயல்படுத்தப்படும் போது சுடும்.

நூல்களை நிறுத்துதல்

பல்வேறு காரணங்களுக்காக, அது தொடங்கிய பிறகு ஓட்டத்தை நிறுத்த வேண்டியிருக்கலாம். இதற்கு பல வழிகள் உள்ளன. நூல் வகுப்பில் இரண்டு முறைகள் சரியாக பெயரிடப்பட்டுள்ளன: கைவிடு и குறுக்கீட்டு. முதலாவது பயன்படுத்த பரிந்துரைக்கப்படவில்லை, ஏனெனில் எந்தவொரு சீரற்ற தருணத்திலும் அதை அழைத்த பிறகு, எந்த அறிவுறுத்தலின் செயலாக்கத்தின் போது, ​​ஒரு விதிவிலக்கு தூக்கி எறியப்படும் ThreadAbortedException. எந்த முழு எண் மாறியையும் அதிகரிக்கும் போது, ​​அத்தகைய விதிவிலக்கு அளிக்கப்படும் என்று நீங்கள் எதிர்பார்க்கவில்லை, இல்லையா? இந்த முறையைப் பயன்படுத்தும் போது, ​​இது மிகவும் உண்மையான சூழ்நிலை. குறியீட்டின் ஒரு குறிப்பிட்ட பிரிவில் CLR அத்தகைய விதிவிலக்கை உருவாக்குவதைத் தடுக்க வேண்டும் என்றால், நீங்கள் அதை அழைப்புகளில் மடிக்கலாம் நூல்.BeginCriticalRegion, நூல்.எண்ட்கிரிட்டிகல் பிராந்தியம். இறுதியாக பிளாக்கில் எழுதப்பட்ட எந்த குறியீடும் அத்தகைய அழைப்புகளில் மூடப்பட்டிருக்கும். இந்த காரணத்திற்காக, கட்டமைப்பின் குறியீட்டின் ஆழத்தில் நீங்கள் ஒரு வெற்று முயற்சியுடன் தொகுதிகளைக் காணலாம், ஆனால் இறுதியாக காலியாக இருக்காது. மைக்ரோசாப்ட் இந்த முறையை மிகவும் ஊக்கப்படுத்துகிறது, அவர்கள் அதை .net கோர் இல் சேர்க்கவில்லை.

குறுக்கீடு முறை மிகவும் கணிக்கக்கூடிய வகையில் செயல்படுகிறது. இது விதிவிலக்குடன் நூலை குறுக்கிடலாம் ThreadInterruptedException நூல் காத்திருக்கும் நிலையில் இருக்கும் தருணங்களில் மட்டுமே. WaitHandle, lock அல்லது Thread.Sleep என்று அழைத்த பிறகு தொங்கிக்கொண்டிருக்கும்போது இந்த நிலையில் நுழைகிறது.

மேலே விவரிக்கப்பட்ட இரண்டு விருப்பங்களும் அவற்றின் கணிக்க முடியாத தன்மை காரணமாக மோசமானவை. ஒரு கட்டமைப்பைப் பயன்படுத்துவதே தீர்வு ரத்து டோக்கன் மற்றும் வகுப்பு CancellationTokenSource. விஷயம் இதுதான்: CancellationTokenSource வகுப்பின் ஒரு உதாரணம் உருவாக்கப்பட்டது மற்றும் அதை வைத்திருப்பவர் மட்டுமே முறையை அழைப்பதன் மூலம் செயல்பாட்டை நிறுத்த முடியும். ரத்து. CancellationToken மட்டுமே செயல்பாட்டிற்கு அனுப்பப்படும். CancellationToken உரிமையாளர்கள் தாங்களாகவே செயல்பாட்டை ரத்து செய்ய முடியாது, ஆனால் செயல்பாடு ரத்து செய்யப்பட்டதா என்பதை மட்டுமே சரிபார்க்க முடியும். இதற்கு ஒரு பூலியன் சொத்து உள்ளது ரத்துசெய்யக் கோரப்பட்டது மற்றும் முறை வீசுதல் ரத்துசெய்யப்பட்டது. பிந்தையவர் ஒரு விதிவிலக்கை வீசுவார் TaskCancelledException ரத்துசெய்யும் டோக்கன் நிகழ்வில் ரத்துசெய்யும் முறை அழைக்கப்பட்டால் கிளி. இந்த முறையை நான் பயன்படுத்த பரிந்துரைக்கிறேன். விதிவிலக்கு செயல்பாடு எந்த நேரத்தில் நிறுத்தப்படலாம் என்பதில் முழு கட்டுப்பாட்டைப் பெறுவதன் மூலம் முந்தைய விருப்பங்களை விட இது ஒரு முன்னேற்றமாகும்.

ஒரு நூலை நிறுத்துவதற்கான மிக கொடூரமான விருப்பம் Win32 API TerminateThread செயல்பாட்டை அழைப்பதாகும். இந்தச் செயல்பாட்டை அழைத்த பிறகு CLR இன் நடத்தை கணிக்க முடியாததாக இருக்கலாம். MSDN இல் இந்த செயல்பாட்டைப் பற்றி பின்வருமாறு எழுதப்பட்டுள்ளது: "டெர்மினேட் த்ரெட் என்பது ஒரு ஆபத்தான செயல்பாடாகும், இது மிகவும் தீவிரமான நிகழ்வுகளில் மட்டுமே பயன்படுத்தப்பட வேண்டும். "

FromAsync முறையைப் பயன்படுத்தி மரபு APIயை பணி அடிப்படையாக மாற்றுகிறது

Tasks அறிமுகப்படுத்தப்பட்டு, பெரும்பாலான டெவலப்பர்களுக்கு அமைதியான திகிலை ஏற்படுத்திய பிறகு தொடங்கப்பட்ட திட்டத்தில் பணிபுரிய உங்களுக்கு அதிர்ஷ்டம் இருந்தால், நீங்கள் பல பழைய APIகளை, மூன்றாம் தரப்பு மற்றும் உங்கள் குழுவைச் சமாளிக்க வேண்டியதில்லை. கடந்த காலத்தில் சித்திரவதை செய்துள்ளார். அதிர்ஷ்டவசமாக, .NET ஃபிரேம்வொர்க் குழு எங்களைக் கவனித்துக்கொண்டது, ஒருவேளை நம்மை நாமே கவனித்துக்கொள்வதே இலக்காக இருக்கலாம். அது எப்படியிருந்தாலும், பழைய ஒத்திசைவற்ற நிரலாக்க அணுகுமுறைகளில் எழுதப்பட்ட குறியீட்டை வலியின்றி புதியதாக மாற்றுவதற்கு .NET பல கருவிகளைக் கொண்டுள்ளது. அவற்றில் ஒன்று, TaskFactory இன் FromAsync முறை. கீழே உள்ள குறியீட்டு எடுத்துக்காட்டில், WebRequest வகுப்பின் பழைய ஒத்திசைவு முறைகளை நான் இந்த முறையைப் பயன்படுத்தி ஒரு Task இல் மடிக்கிறேன்.

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

இது ஒரு எடுத்துக்காட்டு மற்றும் நீங்கள் உள்ளமைக்கப்பட்ட வகைகளில் இதைச் செய்ய வேண்டிய அவசியம் இல்லை, ஆனால் எந்தவொரு பழைய திட்டமும் வெறுமனே IAsyncResult மற்றும் EndDoSomething முறைகளைப் பெறும் BeginDoSomething முறைகளைக் கொண்டுள்ளது.

TaskCompletionSource வகுப்பைப் பயன்படுத்தி மரபு APIயை பணி அடிப்படையாக மாற்றவும்

கருத்தில் கொள்ள வேண்டிய மற்றொரு முக்கியமான கருவி வகுப்பு TaskCompletionSource. செயல்பாடுகள், நோக்கம் மற்றும் செயல்பாட்டுக் கொள்கையின் அடிப்படையில், இது நான் மேலே எழுதிய ThreadPool வகுப்பின் RegisterWaitForSingleObject முறையை ஓரளவு நினைவூட்டுவதாக இருக்கலாம். இந்த வகுப்பைப் பயன்படுத்தி, பழைய ஒத்திசைவற்ற APIகளை எளிதாகவும் வசதியாகவும் பணிகளில் மடிக்கலாம்.

இந்த நோக்கங்களுக்காக வடிவமைக்கப்பட்ட TaskFactory வகுப்பின் FromAsync முறையைப் பற்றி நான் ஏற்கனவே பேசிவிட்டேன் என்று நீங்கள் கூறுவீர்கள். கடந்த 15 ஆண்டுகளில் மைக்ரோசாப்ட் வழங்கிய .net இன் ஒத்திசைவற்ற மாதிரிகளின் வளர்ச்சியின் முழு வரலாற்றையும் இங்கே நாம் நினைவில் கொள்ள வேண்டும்: பணி அடிப்படையிலான ஒத்திசைவற்ற முறைக்கு (TAP) முன்பு, ஒத்திசைவற்ற நிரலாக்க முறை (APP) இருந்தது. முறைகள் பற்றி இருந்தது தொடங்கும்ஏதாவது திரும்ப வருகிறது IAsyncResult மற்றும் முறைகள் முடிவுDoSomething அதை ஏற்றுக்கொள்கிறது மற்றும் இந்த ஆண்டுகளின் பாரம்பரியத்திற்கு FromAsync முறை சரியானது, ஆனால் காலப்போக்கில், அது நிகழ்வு அடிப்படையிலான ஒத்திசைவற்ற முறையால் மாற்றப்பட்டது (ஈ.ஏ.பி.), இது ஒத்திசைவற்ற செயல்பாடு முடிந்ததும் ஒரு நிகழ்வு எழுப்பப்படும் என்று கருதுகிறது.

TaskCompletionSource நிகழ்வு மாதிரியைச் சுற்றி கட்டமைக்கப்பட்ட பணிகள் மற்றும் மரபு APIகளை மூடுவதற்கு ஏற்றது. அதன் பணியின் சாராம்சம் பின்வருமாறு: இந்த வகுப்பின் ஒரு பொருளானது Task என்ற வகையின் பொதுச் சொத்தை கொண்டுள்ளது, இதன் நிலையை TaskCompletionSource வகுப்பின் SetResult, SetException மற்றும் பல முறைகள் மூலம் கட்டுப்படுத்தலாம். இந்த பணிக்கு காத்திருக்கும் ஆபரேட்டர் பயன்படுத்தப்பட்ட இடங்களில், TaskCompletionSource இல் பயன்படுத்தப்படும் முறையைப் பொறுத்து விதிவிலக்குகளுடன் இது செயல்படுத்தப்படும் அல்லது தோல்வியடையும். இது இன்னும் தெளிவாகத் தெரியவில்லை என்றால், இந்த குறியீட்டு உதாரணத்தைப் பார்ப்போம், அங்கு சில பழைய EAP API ஒரு TaskCompletionSource ஐப் பயன்படுத்தி ஒரு டாஸ்க்கில் மூடப்பட்டிருக்கும்: நிகழ்வு சுடும் போது, ​​பணி முடிந்த நிலைக்கு மாற்றப்படும், மேலும் காத்திருக்கும் ஆபரேட்டரைப் பயன்படுத்திய முறை இந்த பணிக்கு பொருளைப் பெற்ற பிறகு அதன் செயல்படுத்தல் மீண்டும் தொடங்கும் விளைவாக.

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களை வடிவமைப்பதற்கான ஒரு சுவாரஸ்யமான வாய்ப்பைத் திறக்கிறது. ஸ்ட்ரீம், நாம் நினைவில் வைத்திருப்பது போல், ஒரு விலையுயர்ந்த ஆதாரம் மற்றும் அவற்றின் எண்ணிக்கை குறைவாக உள்ளது (முக்கியமாக ரேம் அளவு). சிக்கலான வணிக தர்க்கத்துடன் ஏற்றப்பட்ட வலை பயன்பாட்டை உருவாக்குவதன் மூலம் இந்த வரம்பை எளிதாக அடையலாம். நீண்ட வாக்குப்பதிவு போன்ற ஒரு தந்திரத்தை செயல்படுத்தும்போது நான் பேசும் சாத்தியக்கூறுகளைக் கருத்தில் கொள்வோம்.

சுருக்கமாக, தந்திரத்தின் சாராம்சம் இதுதான்: API இலிருந்து அதன் பக்கத்தில் நிகழும் சில நிகழ்வுகளைப் பற்றிய தகவலைப் பெற வேண்டும், அதே நேரத்தில் API, சில காரணங்களால், நிகழ்வைப் புகாரளிக்க முடியாது, ஆனால் மாநிலத்தை மட்டுமே திரும்பப் பெற முடியும். WebSocket காலத்திற்கு முன்பு அல்லது சில காரணங்களால் இந்தத் தொழில்நுட்பத்தைப் பயன்படுத்துவது சாத்தியமில்லாதபோது HTTPயின் மேல் கட்டப்பட்ட அனைத்து APIகளும் இதற்கு எடுத்துக்காட்டு. கிளையன்ட் HTTP சேவையகத்தைக் கேட்கலாம். HTTP சர்வரால் கிளையண்டுடன் தொடர்பைத் தொடங்க முடியாது. டைமரைப் பயன்படுத்தி சர்வரில் வாக்கெடுப்பு நடத்துவதே ஒரு எளிய தீர்வாகும், ஆனால் இது சர்வரில் கூடுதல் சுமையை உருவாக்குகிறது மற்றும் சராசரி டைமர் இன்டர்வல் / 2 இல் கூடுதல் தாமதத்தை உருவாக்குகிறது. இதைப் போக்க, லாங் பாலிங் என்ற தந்திரம் கண்டுபிடிக்கப்பட்டது, இதில் பதிலை தாமதப்படுத்துவது அடங்கும். காலாவதியாகும் வரை அல்லது ஒரு நிகழ்வு நிகழும் வரை சேவையகம். நிகழ்வு ஏற்பட்டால், அது செயலாக்கப்படும், இல்லையெனில், கோரிக்கை மீண்டும் அனுப்பப்படும்.

while(!eventOccures && !timeoutExceeded)  {

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

ஆனால் நிகழ்வுக்காக காத்திருக்கும் வாடிக்கையாளர்களின் எண்ணிக்கை அதிகரித்தவுடன் அத்தகைய தீர்வு பயங்கரமானது என்பதை நிரூபிக்கும், ஏனெனில்... அத்தகைய ஒவ்வொரு வாடிக்கையாளரும் ஒரு நிகழ்விற்காக காத்திருக்கும் முழு நூலையும் ஆக்கிரமித்துள்ளனர். ஆம், நிகழ்வு தூண்டப்படும்போது கூடுதலாக 1ms தாமதத்தைப் பெறுகிறோம், பெரும்பாலும் இது குறிப்பிடத்தக்கதாக இருக்காது, ஆனால் மென்பொருளை அதைவிட மோசமாக்குவது ஏன்? நாம் Thread.Sleep(1) ஐ அகற்றினால், வீணாக ஒரு செயலி கோர் 100% செயலற்ற நிலையில், பயனற்ற சுழற்சியில் சுழலும். 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 ஐ உருவாக்கி அகராதியில் வைப்போம், பின்னர் முதலில் என்ன நடக்கும் என்று காத்திருக்கிறோம்: குறிப்பிட்ட நேர இடைவெளி காலாவதியாகிறது அல்லது ஒரு செய்தி பெறப்படும்.

மதிப்பு பணி: ஏன் மற்றும் எப்படி

அசின்க்/வெயிட் ஆபரேட்டர்கள், விளைச்சல் ரிட்டர்ன் ஆபரேட்டரைப் போலவே, இந்த முறையிலிருந்து ஒரு மாநில இயந்திரத்தை உருவாக்குகிறார்கள், மேலும் இது ஒரு புதிய பொருளை உருவாக்குவதாகும், இது எப்போதும் முக்கியமல்ல, ஆனால் அரிதான சந்தர்ப்பங்களில் இது சிக்கலை உருவாக்கலாம். இந்த வழக்கு உண்மையில் அடிக்கடி அழைக்கப்படும் ஒரு முறையாக இருக்கலாம், நாங்கள் வினாடிக்கு பல்லாயிரக்கணக்கான அழைப்புகளைப் பற்றி பேசுகிறோம். இது போன்ற ஒரு முறை எழுதப்பட்டால், பெரும்பாலான சந்தர்ப்பங்களில் அது அனைத்து காத்திருப்பு முறைகளையும் கடந்து ஒரு முடிவை வழங்கும், பின்னர் .NET இதை மேம்படுத்த ஒரு கருவியை வழங்குகிறது - ValueTask அமைப்பு. அதை தெளிவுபடுத்த, அதன் பயன்பாட்டின் உதாரணத்தைப் பார்ப்போம்: நாம் அடிக்கடி செல்லும் ஒரு தற்காலிக சேமிப்பு உள்ளது. அதில் சில மதிப்புகள் உள்ளன, பின்னர் அவற்றை வெறுமனே திருப்பித் தருகிறோம்; இல்லையென்றால், அவற்றைப் பெற சில மெதுவான IO க்குச் செல்கிறோம். நான் பிந்தையதை ஒத்திசைவற்ற முறையில் செய்ய விரும்புகிறேன், அதாவது முழு முறையும் ஒத்திசைவற்றதாக மாறும். எனவே, முறையை எழுதுவதற்கான தெளிவான வழி பின்வருமாறு:

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

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

சிறிதளவு மேம்படுத்த விரும்புவதால், இந்த குறியீட்டை தொகுக்கும்போது ரோஸ்லின் என்ன உருவாக்குவார் என்ற பயம் காரணமாக, இந்த உதாரணத்தை நீங்கள் பின்வருமாறு மீண்டும் எழுதலாம்:

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, இந்த வழக்கில் வழக்கமான பணியைப் போலவே செயல்படும்.

TaskSchedulers: பணி வெளியீட்டு உத்திகளை நிர்வகித்தல்

நான் கருத்தில் கொள்ள விரும்பும் அடுத்த API வகுப்பு பணி திட்டமிடுபவர் மற்றும் அதன் வழித்தோன்றல்கள். TPL ஆனது இழைகள் முழுவதும் பணிகளை விநியோகிப்பதற்கான உத்திகளை நிர்வகிக்கும் திறனைக் கொண்டுள்ளது என்பதை நான் ஏற்கனவே மேலே குறிப்பிட்டுள்ளேன். இத்தகைய உத்திகள் TaskScheduler வகுப்பின் வழித்தோன்றல்களில் வரையறுக்கப்பட்டுள்ளன. உங்களுக்குத் தேவைப்படும் எந்தவொரு உத்தியும் நூலகத்தில் காணலாம். இணை நீட்டிப்புகள் கூடுதல், மைக்ரோசாப்ட் உருவாக்கியது, ஆனால் .NET இன் பகுதியாக இல்லை, ஆனால் ஒரு Nuget தொகுப்பாக வழங்கப்படுகிறது. அவற்றில் சிலவற்றை சுருக்கமாகப் பார்ப்போம்:

  • CurrentThreadTaskScheduler — தற்போதைய தொடரிழையில் பணிகளைச் செயல்படுத்துகிறது
  • LimitedConcurrencyLevelTaskScheduler - கன்ஸ்ட்ரக்டரில் ஏற்றுக்கொள்ளப்பட்ட N அளவுருவால் ஒரே நேரத்தில் செயல்படுத்தப்படும் பணிகளின் எண்ணிக்கையைக் கட்டுப்படுத்துகிறது.
  • ஆர்டர் செய்யப்பட்ட டாஸ்க் ஷெட்யூலர் — LimitedConcurrencyLevelTaskScheduler(1) என வரையறுக்கப்படுகிறது, எனவே பணிகள் தொடர்ச்சியாக செயல்படுத்தப்படும்.
  • WorkStealing TaskScheduler - செயல்படுத்துகிறது வேலை-திருடுதல் பணி விநியோகத்திற்கான அணுகுமுறை. அடிப்படையில் இது ஒரு தனி த்ரெட்பூல். .NET ThreadPool இல் ஒரு நிலையான வகுப்பு, எல்லா பயன்பாடுகளுக்கும் ஒன்று, அதாவது நிரலின் ஒரு பகுதியில் அதன் ஓவர்லோடிங் அல்லது தவறான பயன்பாடு மற்றொன்றில் பக்க விளைவுகளுக்கு வழிவகுக்கும் என்ற சிக்கலை தீர்க்கிறது. மேலும், இத்தகைய குறைபாடுகளின் காரணத்தை புரிந்துகொள்வது மிகவும் கடினம். அந்த. த்ரெட்பூலின் பயன்பாடு ஆக்ரோஷமானதாகவும் கணிக்க முடியாததாகவும் இருக்கும் நிரலின் சில பகுதிகளில் தனியான WorkStealingTaskSchedulerகளைப் பயன்படுத்த வேண்டிய அவசியம் இருக்கலாம்.
  • QueuedTaskScheduler — முன்னுரிமை வரிசை விதிகளின்படி பணிகளைச் செய்ய உங்களை அனுமதிக்கிறது
  • ThreadPerTaskScheduler - ஒவ்வொரு பணிக்கும் ஒரு தனி நூலை உருவாக்குகிறது. கணிக்க முடியாத அளவுக்கு நீண்ட நேரம் எடுக்கும் பணிகளுக்கு பயனுள்ளதாக இருக்கும்.

நல்ல விவரம் உள்ளது கட்டுரை microsoft வலைப்பதிவில் TaskSchedulers பற்றி.

Tasks தொடர்பான எல்லாவற்றிலும் பிழைத்திருத்தம் செய்ய, விஷுவல் ஸ்டுடியோவில் Tasks சாளரம் உள்ளது. இந்த சாளரத்தில் நீங்கள் பணியின் தற்போதைய நிலையைக் காணலாம் மற்றும் தற்போது செயல்படுத்தப்படும் குறியீட்டின் வரிக்குச் செல்லலாம்.

.NET: மல்டித்ரெடிங் மற்றும் அசின்க்ரோனியுடன் வேலை செய்வதற்கான கருவிகள். பகுதி 1

PLinq மற்றும் இணை வகுப்பு

பணிகள் மற்றும் அவற்றைப் பற்றிச் சொல்லப்பட்ட அனைத்தும் தவிர, .NET இல் இன்னும் இரண்டு சுவாரஸ்யமான கருவிகள் உள்ளன: PLinq (Linq2Parallel) மற்றும் இணை வகுப்பு. பல த்ரெட்களில் அனைத்து லிங்க் செயல்பாடுகளையும் இணையாக செயல்படுத்துவதாக முதல் உறுதியளிக்கிறது. WithDegreeOfParallelism நீட்டிப்பு முறையைப் பயன்படுத்தி நூல்களின் எண்ணிக்கையை உள்ளமைக்க முடியும். துரதிருஷ்டவசமாக, பெரும்பாலும் PLinq ஆனது அதன் இயல்புநிலை பயன்முறையில் குறிப்பிடத்தக்க வேக ஆதாயத்தை வழங்க உங்கள் தரவு மூலத்தின் உள்ளகங்களைப் பற்றிய போதுமான தகவலைக் கொண்டிருக்கவில்லை, மறுபுறம், முயற்சி செய்வதற்கான செலவு மிகவும் குறைவு: நீங்கள் இதற்கு முன் AsParallel முறையை அழைக்க வேண்டும். லிங்க் முறைகளின் சங்கிலி மற்றும் செயல்திறன் சோதனைகளை இயக்கவும். மேலும், பகிர்வுகள் பொறிமுறையைப் பயன்படுத்தி உங்கள் தரவு மூலத்தின் தன்மை பற்றிய கூடுதல் தகவலை PLinq க்கு அனுப்ப முடியும். நீங்கள் மேலும் படிக்கலாம் இங்கே и இங்கே.

பேரலல் ஸ்டாடிக் கிளாஸ், ஃபோர் லூப்பை இணையாக, ஃபார் லூப்பை இயக்குதல் மற்றும் பல பிரதிநிதிகளை இணையான இன்வோக்கில் செயல்படுத்துதல் ஆகியவற்றின் மூலம் ஃபோரீச் சேகரிப்பு மூலம் திரும்ப திரும்ப முறைகளை வழங்குகிறது. கணக்கீடுகள் முடிவடையும் வரை தற்போதைய நூலின் செயலாக்கம் நிறுத்தப்படும். கடைசி வாதமாக ParallelOptions ஐ அனுப்புவதன் மூலம் நூல்களின் எண்ணிக்கையை கட்டமைக்க முடியும். விருப்பங்களைப் பயன்படுத்தி TaskScheduler மற்றும் CancellationToken ஐயும் நீங்கள் குறிப்பிடலாம்.

கண்டுபிடிப்புகள்

எனது அறிக்கையின் உள்ளடக்கம் மற்றும் அதற்குப் பிறகு எனது பணியின் போது நான் சேகரித்த தகவல்களின் அடிப்படையில் இந்த கட்டுரையை எழுதத் தொடங்கியபோது, ​​​​இது இவ்வளவு இருக்கும் என்று நான் எதிர்பார்க்கவில்லை. இப்போது, ​​இந்தக் கட்டுரையை நான் தட்டச்சு செய்யும் உரையாசிரியர், பக்கம் 15 போய்விட்டது என்று என்னைக் குறைகூறும் போது, ​​இடைக்கால முடிவுகளைச் சுருக்கமாகக் கூறுகிறேன். மற்ற தந்திரங்கள், APIகள், காட்சி கருவிகள் மற்றும் ஆபத்துகள் அடுத்த கட்டுரையில் விவாதிக்கப்படும்.

முடிவுகளை:

  • நவீன பிசிக்களின் வளங்களைப் பயன்படுத்த, நூல்கள், ஒத்திசைவு மற்றும் இணையாக வேலை செய்வதற்கான கருவிகளை நீங்கள் அறிந்து கொள்ள வேண்டும்.
  • இந்த நோக்கங்களுக்காக .NET பல்வேறு கருவிகளைக் கொண்டுள்ளது
  • அவை அனைத்தும் ஒரே நேரத்தில் தோன்றவில்லை, எனவே நீங்கள் அடிக்கடி மரபுவழிகளைக் காணலாம், இருப்பினும், அதிக முயற்சி இல்லாமல் பழைய API களை மாற்றுவதற்கான வழிகள் உள்ளன.
  • .NET இல் உள்ள நூல்களுடன் பணிபுரிவது Thread மற்றும் ThreadPool வகுப்புகளால் குறிப்பிடப்படுகிறது
  • Thread.Abort, Thread.Interrupt மற்றும் Win32 API TerminateThread முறைகள் ஆபத்தானவை மற்றும் பயன்படுத்த பரிந்துரைக்கப்படவில்லை. மாறாக, CancellationToken பொறிமுறையைப் பயன்படுத்துவது நல்லது
  • ஓட்டம் ஒரு மதிப்புமிக்க வளம் மற்றும் அதன் வழங்கல் குறைவாக உள்ளது. நிகழ்வுகளுக்காக த்ரெட்கள் பிஸியாக காத்திருக்கும் சூழ்நிலைகள் தவிர்க்கப்பட வேண்டும். இதற்கு TaskCompletionSource வகுப்பைப் பயன்படுத்துவது வசதியானது
  • இணையான மற்றும் ஒத்திசைவின்மையுடன் பணிபுரிவதற்கான மிகவும் சக்திவாய்ந்த மற்றும் மேம்பட்ட .NET கருவிகள் Tasks ஆகும்.
  • c# async/waiit ஆபரேட்டர்கள் தடுக்காத காத்திருப்பு என்ற கருத்தை செயல்படுத்துகின்றனர்
  • TaskScheduler-பெறப்பட்ட வகுப்புகளைப் பயன்படுத்தி த்ரெட்கள் முழுவதும் பணிகளின் விநியோகத்தை நீங்கள் கட்டுப்படுத்தலாம்
  • ஹாட்-பாத் மற்றும் மெமரி-ட்ராஃபிக்கை மேம்படுத்துவதற்கு ValueTask அமைப்பு பயனுள்ளதாக இருக்கும்
  • விஷுவல் ஸ்டுடியோவின் பணிகள் மற்றும் நூல்கள் சாளரங்கள் பல-திரிக்கப்பட்ட அல்லது ஒத்திசைவற்ற குறியீட்டை பிழைத்திருத்துவதற்குப் பயனுள்ள பல தகவல்களை வழங்குகின்றன.
  • PLinq ஒரு சிறந்த கருவியாகும், ஆனால் அதில் உங்கள் தரவு மூலத்தைப் பற்றிய போதுமான தகவல்கள் இல்லாமல் இருக்கலாம், ஆனால் பகிர்வு பொறிமுறையைப் பயன்படுத்தி இதை சரிசெய்யலாம்.
  • தொடர வேண்டும் ...

ஆதாரம்: www.habr.com

கருத்தைச் சேர்