.NET: ከብዙ-ክር እና ተመሳሳይነት ጋር ለመስራት የሚረዱ መሳሪያዎች. ክፍል 1

በሀብር ላይ ዋናውን መጣጥፍ አሳትሜአለሁ፣ ትርጉሙም በድርጅት ውስጥ ተለጠፈ ብሎግ መለጠፍ.

ውጤቱን እዚህ እና አሁን ሳይጠብቁ ፣ ወይም ብዙ ስራዎችን በሚሰሩት በርካታ ክፍሎች መካከል የመከፋፈል አስፈላጊነት ባልተመሳሰል ሁኔታ ፣ ኮምፒውተሮች ከመምጣታቸው በፊት ነበር። ከመልካቸው ጋር, ይህ ፍላጎት በጣም ተጨባጭ ሆኗል. አሁን ፣ በ 2019 ፣ ይህንን ጽሑፍ በላፕቶፕ ላይ ባለ ባለ 8-ኮር ኢንቴል ኮር ፕሮሰሰር ፣ አንድ መቶ ሂደቶች ያልነበሩበት ፣ ግን የበለጠ ክሮች በትይዩ እየሰሩ ነው። በአቅራቢያው፣ ከጥቂት አመታት በፊት የተገዛ፣ ትንሽ የሚረብሽ ስልክ አለ፣ በቦርዱ ላይ ባለ 8-ኮር ፕሮሰሰር አለው። የቲማቲክ ሃብቶች ደራሲዎቻቸው 16-ኮር ፕሮሰሰሮችን ባደረጉበት በዚህ አመት ዋና ዋና ስማርትፎኖች በሚያደንቁባቸው ጽሑፎች እና ቪዲዮዎች የተሞሉ ናቸው። MS Azure 20 ኮሮች እና 128 ቴባ ራም ያለው ቨርቹዋል ማሽን በሰአት ከ2 ዶላር ባነሰ ዋጋ ያቀርባል። እንደ አለመታደል ሆኖ የክርን መስተጋብር ማስተዳደር ሳይቻል ከፍተኛውን ለማውጣት እና ይህንን ኃይል ለመግታት የማይቻል ነው።

ቃላት ትርጓሜ

ሂደት - የስርዓተ ክወና ነገር፣ የተናጠል የአድራሻ ቦታ፣ ክሮች ይዟል።
ክር - የስርዓተ ክወናው ነገር ፣ ትንሹ የአፈፃፀም ክፍል ፣ የሂደቱ አካል ፣ ክሮች በሂደቱ ውስጥ ማህደረ ትውስታን እና ሌሎች ሀብቶችን ይጋራሉ።
ባለብዙ ማደራጀት - የስርዓተ ክወናው ንብረት ፣ ብዙ ሂደቶችን በተመሳሳይ ጊዜ የማስፈፀም ችሎታ
ባለብዙ-ኮር - የአቀነባባሪው ንብረት ፣ ለመረጃ ሂደት ብዙ ኮርዎችን የመጠቀም ችሎታ
ባለብዙ ሂደት - የኮምፒተር ንብረት ፣ በአካል ከብዙ ፕሮሰሰር ጋር በአንድ ጊዜ የመስራት ችሎታ
ባለ ብዙ ማነበብ - የሂደቱ ንብረት ፣ የውሂብ ሂደትን በበርካታ ክሮች መካከል የማሰራጨት ችሎታ።
ትይዩነት - በአንድ ጊዜ ውስጥ ብዙ ተግባሮችን በአካል በአንድ ጊዜ ማከናወን
አልተመሳሰልም። - ይህ ሂደት እስኪጠናቀቅ ድረስ ሳይጠብቅ የቀዶ ጥገናው አፈፃፀም ፣ የአፈፃፀም ውጤቱ በኋላ ላይ ሊከናወን ይችላል።

ዘይቤ

ሁሉም ትርጓሜዎች ጥሩ አይደሉም እና አንዳንዶቹ ተጨማሪ ማብራሪያ ያስፈልጋቸዋል፣ ስለዚህ ቁርስን ስለማዘጋጀት ዘይቤያዊ በሆነ መንገድ ወደተዋወቀው የቃላት አነጋገር እጨምራለሁ። በዚህ ዘይቤ ቁርስ ማድረግ ሂደት ነው።

ጠዋት ላይ ቁርስ በማዘጋጀት ላይሲፒዩወደ ኩሽና መጡ (ኮምፒውተር). 2 እጅ አለኝቀለማት). ወጥ ቤቱ በርካታ የቤት ዕቃዎች አሉትIO): ምድጃ, ማንቆርቆሪያ, toaster, ማቀዝቀዣ. ጋዙን አብራው ፣ መጥበሻውን በላዩ ላይ አድርጌው እና ዘይት ውስጥ አፍስሳለሁ ፣ እስኪሞቅ ድረስ ሳልጠብቅ (ሳይመሳሰል፣ የማይከለክል-IO-ቆይእንቁላሎቹን ከማቀዝቀዣው ውስጥ አውጥቼ ወደ ሳህን ውስጥ እሰብራለሁ ፣ ከዚያ በኋላ በአንድ እጄ እመታለሁ (ክር #1) እና ሁለተኛ (ክር #2) ሳህኑን (የተጋራ መገልገያ) ይያዙ. አሁን ማንኪያውን እከፍት ነበር ፣ ግን በቂ እጆች የሉም (ክር ረሃብ) በዚህ ጊዜ መጥበሻው ይሞቃል (ውጤቱን በማስኬድ) የገረፍኩትን እፈስሳለሁ። ማሰሮውን ያዝኩ እና አብራው እና ውሃው ሲፈላ በሞኝነት ተመለከትኩ (ማገድ-አይኦ-ቆይምንም እንኳን በዚህ ጊዜ ኦሜሌውን የገረፍኩበትን ሳህን ማጠብ እችላለሁ።

ኦሜሌን በ 2 እጆቼ ብቻ አብስዬ ነበር, እና ተጨማሪ የለኝም, ግን በተመሳሳይ ጊዜ, ኦሜሌውን በሚመታበት ጊዜ, በአንድ ጊዜ 3 ስራዎች ተካሂደዋል: ኦሜሌውን መገረፍ, ሳህኑን በመያዝ, ድስቱን ማሞቅ. ሲፒዩ የኮምፒዩተር ፈጣኑ አካል ነው ፣አይኦ ብዙ ጊዜ ሁሉንም ነገር ያዘገየዋል ፣ስለዚህ ብዙ ጊዜ ውጤታማ መፍትሄ መረጃ ከአይኦ እየደረሰ እያለ ሲፒዩን በአንድ ነገር መያዝ ነው።

ዘይቤውን በመቀጠል፡-

  • ኦሜሌን በማብሰል ሂደት ውስጥ ከሆነ ልብሶችን ለመለወጥ እሞክራለሁ, ይህ የብዙ ስራዎች ምሳሌ ይሆናል. ጠቃሚ ነጥብ፡ ኮምፒውተሮች በዚህ ረገድ ከሰዎች በጣም የተሻሉ ናቸው።
  • እንደ ሬስቶራንት ያሉ ብዙ ሼፎች ያሉት ኩሽና ባለ ብዙ ኮር ኮምፒውተር ነው።
  • በገበያ ማዕከሉ ውስጥ ባለው የምግብ ፍርድ ቤት ውስጥ ብዙ ምግብ ቤቶች - የውሂብ ማዕከል

NET መሳሪያዎች

በክር ውስጥ፣ ልክ እንደሌሎች ብዙ ነገሮች፣ .NET ጥሩ ነው። በእያንዳንዱ አዲስ ስሪት ከእነሱ ጋር አብሮ ለመስራት ተጨማሪ እና ተጨማሪ አዳዲስ መሳሪያዎችን ያስተዋውቃል፣ በስርዓተ ክወና ክሮች ላይ አዲስ የአብስትራክት ንብርብሮች። ከግንባታ ማጠቃለያዎች ጋር በሚሰሩበት ጊዜ የክፈፍ ገንቢዎች አንድ ወይም ከዚያ በላይ ደረጃዎችን ወደ ታች ለመውረድ እድሉን የሚተው አካሄድ ይጠቀማሉ። ብዙውን ጊዜ ይህ አስፈላጊ አይደለም, በተጨማሪም, እራስዎን በጥይት እራስን ለመምታት እድል ይከፍታል, ነገር ግን አንዳንድ ጊዜ, አልፎ አልፎ, ችግሩን ለመፍታት ብቸኛው መንገድ ሊሆን ይችላል. አሁን ያለው የአብስትራክሽን ደረጃ.

በመሳሪያዎች ማለቴ ሁለቱንም የፕሮግራሚንግ በይነገጽ (ኤፒአይኤስ) በማዕቀፉ እና በሶስተኛ ወገን ፓኬጆች የተሰጡ እንዲሁም ሙሉ የሶፍትዌር መፍትሄ ከብዙ-ክር ኮድ ጋር የተያያዙ ችግሮችን በቀላሉ ለማግኘት ያስችላል።

ክር መጀመር

የ Thread ክፍል በ NET ውስጥ በጣም መሠረታዊው የክር ክፍል ነው። ገንቢው ከሁለት ተወካዮች አንዱን ይቀበላል፡-

  • ThreadStart - ምንም መለኪያዎች የሉም
  • ParametrizedThreadStart - ከአንድ ግቤት አይነት ነገር ጋር።

ተወካዩ የጀምር ዘዴን ከጠራ በኋላ አዲስ በተፈጠረው ክር ውስጥ ይፈጸማል፣የፓራሜትራይዝድ ትሬድስታርት አይነት ልዑካን ለግንባታው ከተላለፈ አንድ ነገር ወደ ጀምር ዘዴ መተላለፍ አለበት። ይህ ዘዴ ማንኛውንም የአካባቢ መረጃ ወደ ዥረቱ ለማስተላለፍ ያስፈልጋል። ክር መፍጠር በጣም ውድ ስራ እንደሆነ እና ክሩ ራሱ ከባድ ነገር እንደሆነ ልብ ሊባል የሚገባው ቢያንስ በአንድ ቁልል 1 ሜባ ማህደረ ትውስታን ስለሚመድብ እና ከስርዓተ ክወናው ኤፒአይ ጋር መስተጋብር ስለሚያስፈልገው ነው።

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

የ ThreadPool ክፍል የመዋኛ ጽንሰ-ሀሳብን ይወክላል። በ NET ውስጥ ፣ የክር ገንዳው የምህንድስና ቁራጭ ነው እና በማይክሮሶፍት ውስጥ ያሉ ገንቢዎች በብዙ ሁኔታዎች ውስጥ በጥሩ ሁኔታ እንዲሠራ ለማድረግ ብዙ ጥረት አድርገዋል።

አጠቃላይ ጽንሰ-ሀሳብ

ከተጀመረበት ጊዜ ጀምሮ አፕሊኬሽኑ በመጠባበቂያ ውስጥ በርካታ ክሮች ከበስተጀርባ ይፈጥራል እና እነሱን ለመጠቀም እድሉን ይሰጣል። ክሮች በተደጋጋሚ እና በብዛት ጥቅም ላይ ከዋሉ, ገንዳው የጥሪ ኮድ ፍላጎቶችን ለማሟላት ይሰፋል. በገንዳው ውስጥ በትክክለኛው ጊዜ ነፃ ክሮች ከሌሉ ፣ ከክሩ ውስጥ አንዱን እስኪመለስ ድረስ ይጠብቃል ወይም አዲስ ይፈጥራል። ከዚህ በመነሳት የክር ገንዳው ለአንዳንድ አጫጭር ድርጊቶች በጣም ጥሩ እና በመተግበሪያዎች ህይወት ውስጥ እንደ አገልግሎት ለሚሰሩ ስራዎች በጣም ተስማሚ ነው.

ከመዋኛ ገንዳው ላይ ክር ለመጠቀም የWaitCallback አይነት ተወካይ የሚወስድ የQueueUserWorkItem ዘዴ አለ፣ እሱም ከፓራሜትራይዝድ ትሪድስታርት ፊርማ ጋር የሚዛመድ እና ወደ እሱ የተላለፈው ግቤት ተመሳሳይ ተግባር ያከናውናል።

ThreadPool.QueueUserWorkItem(...);

ብዙም ያልታወቀ የክር ገንዳ ዘዴ፣ RegisterWaitForSingleObject፣ የማይከለክለው IO ስራዎችን ለማደራጀት ስራ ላይ ይውላል። ወደዚህ ዘዴ የተላለፈው ልዑካን ወደ ዘዴው ያለፈው WaitHandle ሲለቀቅ ይጠራል።

ThreadPool.RegisterWaitForSingleObject(...)

NET ክር የሰዓት ቆጣሪ አለው እና ከዊንፎርምስ/WPF ጊዜ ቆጣሪዎች የሚለየው ተቆጣጣሪው ከገንዳው በተወሰደ ክር ላይ ይጠራል።

System.Threading.Timer

ለግድያ ልዑካንን ከገንዳው ወደ ክር ለመላክ በጣም ልዩ የሆነ መንገድ አለ - የ BeginInvoke ዘዴ።

DelegateInstance.BeginInvoke

እንዲሁም ከላይ የተጠቀሱትን አብዛኛዎቹን ዘዴዎች በሚጠራው ተግባር ላይ በአጭሩ ማተኮር እፈልጋለሁ - CreateThread from Kernel32.dll Win32 API. ይህንን ተግባር ለመጥራት ለውጫዊ ዘዴዎች ዘዴ ምስጋና ይግባውና አንድ መንገድ አለ. እንዲህ ዓይነቱን ጥሪ አንድ ጊዜ ብቻ በጣም አስፈሪ በሆነው የቅርስ ኮድ ምሳሌ ውስጥ አይቻለሁ፣ እና ያንን ያደረገው ደራሲው ተነሳሽነት አሁንም ለእኔ እንቆቅልሽ ነው።

Kernel32.dll CreateThread

ክሮች መመልከት እና ማረም

በራስዎ የተፈጠሩ ክሮች፣ ሁሉም የሶስተኛ ወገን አካላት እና የ .NET ገንዳ በ Visual Studio Threads መስኮት ውስጥ ሊታዩ ይችላሉ። ይህ መስኮት ስለ ክሮች መረጃ የሚያሳየው አፕሊኬሽኑ በማረም ላይ ሲሆን እና በእረፍት ሁነታ ላይ ሲሆን ብቻ ነው። እዚህ የእያንዳንዱን ክር የቁልል ስሞችን እና ቅድሚያ የሚሰጣቸውን ነገሮች በአመቺ ሁኔታ ማየት ይችላሉ፣ ማረም ወደ አንድ የተወሰነ ክር ይቀይሩ። በክር ክፍል የቅድሚያ ንብረት፣ የክርን ቅድሚያ ማዘጋጀት ትችላላችሁ፣ ይህም ኦሲ እና CLR በክር መካከል የአቀነባባሪ ጊዜ ሲካፈሉ እንደ ምክር ይወስዳሉ።

.NET: ከብዙ-ክር እና ተመሳሳይነት ጋር ለመስራት የሚረዱ መሳሪያዎች. ክፍል 1

ተግባር ትይዩ ቤተ መጻሕፍት

የተግባር ትይዩ ቤተ መፃህፍት (TPL) በ NET 4.0 ውስጥ ቀርቧል። አሁን ከአሲክሮኒ ጋር ለመስራት መደበኛ እና ዋናው መሳሪያ ነው. የቆዩ አቀራረቦችን የሚጠቀም ማንኛውም ኮድ እንደ ውርስ ይቆጠራል። የTPL መሰረታዊ አሃድ ከሲስተም.Threading.Tasks የስም ቦታ የተግባር ክፍል ነው። ተግባር በክር ላይ ያለ ረቂቅ ነው። በአዲሱ የC# ቋንቋ፣ ከተግባሮች ጋር ለመስራት የሚያምር መንገድ አግኝተናል - መግለጫዎችን ማመሳሰል/መጠባበቅ። እነዚህ ፅንሰ-ሀሳቦች ያልተመሳሰለ ኮድን ቀላል እና የተመሳሰለ ያህል እንዲጽፉ አስችሏቸዋል፣ ይህም ስለ ክሮች ውስጣዊ አሠራር ብዙም ግንዛቤ ለሌላቸው ሰዎች እንኳን ረጅም ስራዎችን በሚሰሩበት ጊዜ የማይቀዘቅዙ መተግበሪያዎችን የሚጠቀሙ መተግበሪያዎችን እንዲጽፉ አስችሏቸዋል። async/wait መጠቀም የአንድ ወይም የበለጡ ጽሑፎች ርዕስ ነው፣ነገር ግን ነጥቡን በጥቂት ዓረፍተ ነገሮች ለመረዳት እሞክራለሁ።

  • async ተግባርን ወይም ባዶነትን የሚመልስ ዘዴ መቀየሪያ ነው።
  • እና የሚጠበቀው የተግባር የማያግድ የጥበቃ ኦፕሬተር ነው።

አሁንም: ተጠባባቂው ኦፕሬተር, በአጠቃላይ ሁኔታ (ልዩነቶች አሉ), የአሁኑን የአፈፃፀም ክር የበለጠ ይለቃሉ, እና ተግባሩ አፈፃፀሙን ሲያጠናቅቅ, እና ክር (በእርግጥ, አውድ መናገሩ የበለጠ ትክክል ነው, ነገር ግን). ከዚያ በኋላ) ዘዴውን የበለጠ መተግበሩን ለመቀጠል ነፃ ይሆናል። በ NET ውስጥ ፣ ይህ ዘዴ እንደ ምርት መመለሻ በተመሳሳይ መንገድ ይተገበራል ፣ የጽሑፍ ዘዴ ወደ አጠቃላይ ክፍል ሲቀየር ፣ የግዛት ማሽን እና በእነዚህ ግዛቶች ላይ በመመርኮዝ በተናጥል ሊተገበር ይችላል። ፍላጎት ያለው ማንኛውም ሰው async / በመጠባበቅ ፣ በማጠናቀር እና ስብሰባውን JetBrains dotPeek በ Compiler Generated Code የነቃ በመጠቀም ማንኛውንም ቀላል ኮድ መፃፍ ይችላል።

ተግባርን ለመጀመር እና ለመጠቀም አማራጮችን ያስቡ። ከዚህ በታች ባለው ምሳሌ ኮድ ምንም የማይጠቅም አዲስ ተግባር እንፈጥራለን (ክር. እንቅልፍ (10000)), ነገር ግን በእውነተኛ ህይወት ውስጥ አንዳንድ ውስብስብ ሲፒዩ-ተኮር ስራ መሆን አለበት.

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 ስራው በፍጥነት እንደማይጠናቀቅ ፍንጭ ነው, ይህ ማለት ምናልባት ከገንዳው ላይ ክር ላለመውሰድ ማሰብ አለብዎት, ነገር ግን ቀሪውን ላለመጉዳት ለዚህ ተግባር የተለየ መፍጠር አለብዎት.
  • ተያይዘው ወደ ወላጅ - ተግባራት በተዋረድ ውስጥ ሊሰለፉ ይችላሉ። ይህ አማራጭ ጥቅም ላይ የዋለ ከሆነ, ተግባሩ እራሱ ባጠናቀቀበት እና ልጆቹ እስኪያጠናቅቁ ድረስ በመጠባበቅ ላይ ሊሆን ይችላል.
  • PreferFairness - ማለት በኋላ ላይ ከተላኩት በፊት ለአፈፃፀም የተላኩ ተግባራትን ማከናወን ጥሩ ይሆናል ማለት ነው። ግን ይህ ምክር ብቻ ነው ውጤቱም ዋስትና የለውም.

ወደ ዘዴው የተላለፈው ሁለተኛው ግቤት CancelationToken ነው። ክዋኔው ከጀመረ በኋላ መሰረዙን በትክክል ለማስተናገድ፣ እየተሰራ ያለው ኮድ በCancelationToken ሁኔታ ላይ ባሉ ፍተሻዎች መሞላት አለበት። ምንም ቼኮች ከሌሉ በCancelationTokenSource ነገር ላይ የተጠራው የስረዛ ዘዴ ተግባሩ ከመጀመሩ በፊት ብቻ ነው ማስቆም የሚችለው።

የመጨረሻው መለኪያ የተግባር መርሐግብር አይነት መርሐግብር አውጪ ነገር ነው። ይህ ክፍል እና ዘሮቹ የተነደፉት ተግባራትን በክሮች ውስጥ ለማከፋፈል ስልቶችን ለመቆጣጠር ነው፣ በነባሪነት ተግባር ከገንዳው በዘፈቀደ ክር ላይ ይከናወናል።

ተጠባባቂው ኦፕሬተር በተፈጠረው ተግባር ላይ ይተገበራል ፣ ይህ ማለት ከሱ በኋላ የተፃፈው ኮድ ካለ ፣ ከተጠባባቂው በፊት ካለው ኮድ ጋር በተመሳሳይ አውድ (ብዙውን ጊዜ ይህ ማለት በተመሳሳይ ክር ላይ) ይከናወናል ማለት ነው ።

ዘዴው እንደ assync void ምልክት ተደርጎበታል፣ ይህ ማለት ተጠባባቂውን ኦፕሬተር እንዲጠቀም ይፈቀድለታል፣ ነገር ግን የጥሪ ቁጥሩ እስኪፈጸም ድረስ መጠበቅ አይችልም። ይህ ችሎታ የሚያስፈልግ ከሆነ, ዘዴው አንድ ተግባር መመለስ አለበት. ያልተመሳሳይ ባዶነት ምልክት የተደረገባቸው ዘዴዎች በጣም የተለመዱ ናቸው: እንደ አንድ ደንብ, እነዚህ የክስተት ተቆጣጣሪዎች ወይም ሌሎች በእሳት መርህ ላይ የሚሰሩ እና የመርሳት ዘዴዎች ናቸው. ግድያው እስኪጠናቀቅ ድረስ ለመጠበቅ እድሉን መስጠት ብቻ ሳይሆን ውጤቱን ለመመለስ አስፈላጊ ከሆነ ተግባርን መጠቀም አስፈላጊ ነው.

የStartNew ዘዴ በተመለሰው ተግባር ላይ ፣ነገር ግን ፣እንደማንኛውም ፣ የ ConfigureAwait ዘዴን በውሸት ግቤት መጥራት ይችላሉ ፣ከዚያም ከተጠባበቁ በኋላ አፈፃፀም የሚቀጥሉት በተያዘው አውድ ላይ ሳይሆን በዘፈቀደ ነው። ይህ ከተጠባባቂው በኋላ የአፈፃፀም አውድ ለኮዱ አስፈላጊ በማይሆንበት ጊዜ ሁሉ መደረግ አለበት. እንዲሁም በቤተ-መጽሐፍት ውስጥ ተጠቅልሎ የሚደርሰው ኮድ ሲጽፍ ከኤምኤስ የተሰጠ ምክር ነው።

ተግባራቱ እስኪጠናቀቅ ድረስ እንዴት መጠበቅ እንደሚችሉ ላይ ትንሽ እንቆይ። ከዚህ በታች የኮድ ምሳሌ አለ፣ ጥበቃው በሁኔታዊ ሁኔታ ጥሩ ሲሆን እና ሁኔታዊ በሆነ ጊዜ መጥፎ በሚሆንበት ጊዜ ላይ አስተያየቶች ያሉት።

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
}

በመጀመሪያው ምሳሌ, የመደወያውን ክር ሳይገድብ ስራው እስኪጠናቀቅ ድረስ እንጠብቃለን, ውጤቱን ወደ ማቀናበር የምንመለሰው ቀድሞውኑ በሚገኝበት ጊዜ ብቻ ነው, እስከዚያ ድረስ የመደወያው ክር በራሱ ይቀራል.

በሁለተኛው አማራጭ ዘዴው ውጤቱ እስኪሰላ ድረስ የመደወያውን ክር እንዘጋለን. ይህ መጥፎ ነው ምክንያቱም እኛ ፈትል, እንዲህ ያለ ጠቃሚ ፕሮግራም ሀብት, ቀላል ስራ ፈትነት ጋር, ነገር ግን ደግሞ የምንጠራው ዘዴ ኮድ ውስጥ መጠበቅ ካለ ብቻ አይደለም, እና የማመሳሰል አውድ ወደ ጥሪ ክር መመለስን ያካትታል. ከተጠባበቀ በኋላ እኛ እንዘጋለን-የጥሪው ክር ያልተመሳሰለውን ዘዴ ለመገምገም ውጤቱን እየጠበቀ ነው ፣ ያልተመሳሰለው ዘዴ በጥሪው ክር ውስጥ መፈጸሙን ለመቀጠል በከንቱ ይሞክራል።

የዚህ አሰራር ሌላው ጉዳት ውስብስብ የስህተት አያያዝ ነው. እውነታው ግን asynchronous code ውስጥ ያሉ ስህተቶች async / wait ን ሲጠቀሙ ለማስተናገድ በጣም ቀላል ናቸው - ኮዱ የተመሳሰለ ከሆነ ተመሳሳይ ባህሪ አላቸው። የተመሳሰለ መጠበቅ ማስወጣትን ለተግባር ከተጠቀምንበት፣የመጀመሪያው ልዩነት በAggregateException ተጠቅልሎአል፣ማለትም። ልዩነቱን ለማስተናገድ በC # አለም ውስጥ የበለጠ ከሚታወቀው የያጅ ብሎክ ሰንሰለት ይልቅ የ InnerException አይነትን ማሰስ እና ሰንሰለቱን እራስዎ በአንድ መያዣ ብሎክ ውስጥ ይፃፉ ወይም ሲገነቡ መያዣውን ይጠቀሙ።

ሦስተኛው እና የመጨረሻዎቹ ምሳሌዎች በተመሳሳይ ምክንያት መጥፎ ተብለው ምልክት የተደረገባቸው እና ሁሉንም ተመሳሳይ ችግሮች ይይዛሉ።

መቼም እና ሁሉም ዘዴዎች የተግባር ቡድንን ሲጠብቁ እጅግ በጣም ምቹ ሲሆኑ የተግባር ቡድንን ወደ አንድ ያጠቃለላሉ ከቡድኑ ውስጥ በመጀመሪያው ተግባር ላይ ወይም ሁሉም ሰው አፈፃፀማቸውን ሲያጠናቅቁ።

የማቆሚያ ክሮች

በተለያዩ ምክንያቶች ክር ከጀመረ በኋላ ማቆም አስፈላጊ ሊሆን ይችላል. ይህንን ለማድረግ በርካታ መንገዶች አሉ. የ Thread ክፍል ተገቢ ስሞች ያላቸው ሁለት ዘዴዎች አሉት - እነዚህ ናቸው አስወገደ и አቋረጠ. የመጀመሪያው ለአጠቃቀም በጣም የተከለከለ ነው, ምክንያቱም. ከጥሪው በኋላ በማንኛውም የዘፈቀደ ቅጽበት ፣ በማንኛውም መመሪያ ሂደት ወቅት ፣ ልዩ ሁኔታ ይጣላል ThreadAbortedException. የኢንቲጀር ተለዋዋጭ ሲጨምር እንደዚህ ያለ ልዩ ሁኔታ ይጣላል ብለው አይጠብቁም ፣ አይደል? እና ይህን ዘዴ ሲጠቀሙ, ይህ በጣም ተጨባጭ ሁኔታ ነው. CLR እንደዚህ ያለ ልዩ ሁኔታን በተወሰነ የኮድ ክፍል ውስጥ እንዳይጥል መከላከል ከፈለጉ በጥሪዎች መጠቅለል ይችላሉ ክር.ጀማሪ ክሪቲካል ክልል, Thread.EndCriticalክልል. በመጨረሻው እገዳ ውስጥ የተጻፈ ማንኛውም ኮድ ወደ እንደዚህ ዓይነት ጥሪዎች ይቀየራል። በዚህ ምክንያት ፣ በማዕቀፉ ኮድ አንጀት ውስጥ ፣ ባዶ ሙከራን በመጠቀም ብሎኮችን ማግኘት ይችላሉ ፣ ግን በመጨረሻ ባዶ አይደለም። ማይክሮሶፍት ይህንን ዘዴ በጣም ተስፋ ስለሚያደርገው በ .net core ውስጥ አላካተቱም.

የማቋረጡ ዘዴ የበለጠ መተንበይ ይሰራል። በተለየ ሁኔታ ክርውን ሊያቋርጥ ይችላል ThreadInterruptedException ክሩ በመጠባበቅ ሁኔታ ውስጥ በሚሆንበት ጊዜ ብቻ. ወደዚህ ሁኔታ የሚመጣው WaitHandleን በመጠባበቅ ላይ እያለ በማንጠልጠል፣ በመቆለፍ ወይም Thread.Sleep ከጠራ በኋላ ነው።

ከላይ የተገለጹት ሁለቱም አማራጮች ለመተንበይ አለመቻላቸው መጥፎ ናቸው። መውጫው አወቃቀሩን መጠቀም ነው የስረዛ ማስመሰያ እና ክፍል ስረዛTokenSource. ዋናው ነገር ይህ ነው፡ የCancelationTokenSource ክፍል አንድ ምሳሌ ተፈጥሯል እና የእሱ ባለቤት የሆነው ብቻ ዘዴውን በመደወል ቀዶ ጥገናውን ማቆም ይችላል. ሰርዝ. ወደ ቀዶ ጥገናው የሚተላለፈው የCancelationToken ብቻ ነው። የCancelationToken ባለቤቶች ቀዶ ጥገናውን ራሳቸው መሰረዝ አይችሉም፣ ነገር ግን ክዋኔው መሰረዙን ብቻ ማረጋገጥ ይችላሉ። ለዚህ የቦሊያን ንብረት አለ። እንዲሰረዝ ተጠይቋል እና ዘዴ ከተሰረዘ መጣል. የኋለኛው የተለየ ነገር ይጥላል ተግባር ተሰርዟል ልዩ የስረዛ ስልቱ የተጠራው በCancelationTokenSource ምሳሌ ላይ የስረዛ ቶከንን ያጠናከረ ከሆነ። እና እኔ የምመክረው ዘዴ ይህ ነው። ለየት ያለ ቀዶ ጥገና ሊቋረጥ በሚችልበት ጊዜ ሙሉ ቁጥጥርን በመስጠት ይህ ካለፉት አማራጮች የተሻለ ነው።

ክርን ለማቆም በጣም አረመኔው መንገድ Win32 API TerminateThread ተግባርን መደወል ነው። ይህንን ተግባር ከጠራ በኋላ የ CLR ባህሪ ያልተጠበቀ ሊሆን ይችላል። በኤምኤስዲኤን ላይ ስለዚህ ተግባር የሚከተለው ተጽፏል፡- "TerminateThread በጣም ከባድ በሆኑ ጉዳዮች ላይ ብቻ ጥቅም ላይ መዋል ያለበት አደገኛ ተግባር ነው። ”

ከAsync ዘዴን በመጠቀም የቆየ ኤፒአይን ወደ ተግባር በመቀየር ላይ

ተግባራት ከገቡ በኋላ በተጀመረው ፕሮጀክት ላይ ለመስራት እድለኛ ከሆንክ እና የአብዛኞቹን ገንቢዎች ጸጥ ያለ ስጋት ካልቀሰቀስክ ብዙ የቆዩ ኤፒአይዎችን ማለትም ሁለቱንም የሶስተኛ ወገን ማስተናገድ አይኖርብህም። እና ቡድንዎ ከዚህ በፊት ያሰቃያቸው። እንደ እድል ሆኖ፣ ግቡ እራሳችንን መንከባከብ ሊሆን ቢችልም የ.NET Framework ልማት ቡድን እኛን ይንከባከባል። ያም ሆነ ይህ፣ NET በአሮጌው ያልተመሳሰሉ ፕሮግራሚንግ አቀራረቦች ወደ አዲሱ የተፃፈውን ኮድ ያለምንም ህመም ለመቀየር በርካታ መሳሪያዎች አሉት። ከመካከላቸው አንዱ የFromAsync የተግባር ፋብሪካ ዘዴ ነው። ከዚህ በታች ባለው የኮድ ምሳሌ፣ የዌብ መጠየቂያ ክፍልን የድሮውን ያልተመሳሰሉ ዘዴዎች ይህንን ዘዴ ተጠቅሜ በተግባር እጠቀልላለሁ።

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

ይህ አንድ ምሳሌ ብቻ ነው እና ይህን አብሮ በተሰራው አይነት ማድረግ አይጠበቅብዎትም ነገር ግን ማንኛውም የቆየ ፕሮጄክት በቀላሉ በ BeginDoSomething ዘዴዎች እየተጨናነቀ ነው IAsyncResult እና EndDoSomething ዘዴዎችን ሲቀበሉ።

የተግባር ማጠናቀቂያ ምንጭ ክፍልን በመጠቀም የቆየ ኤፒአይን ወደ ተግባር በመቀየር ላይ

ሊታሰብበት የሚገባው ሌላው አስፈላጊ መሳሪያ ክፍል ነው የተግባር ማጠናቀቂያ ምንጭ. ከተግባሮች፣ አላማ እና የአሰራር መርህ አንፃር፣ ከላይ የፃፍኩትን የ ThreadPool ክፍል RegisterWaitForSingleObject ዘዴን በመጠኑ ሊመስል ይችላል። ይህንን ክፍል በመጠቀም የድሮ ያልተመሳሰሉ ኤፒአይዎችን በተግባሮች ውስጥ በቀላሉ እና በተመች ሁኔታ መጠቅለል ይችላሉ።

ለዚህ ዓላማ ስለ TaskFactory ክፍል ፍሮምአሲንክ ዘዴ አስቀድሜ ተናግሬያለሁ ትላለህ። እዚህ ላይ ማይክሮሶፍት ላለፉት 15 ዓመታት ሲያቀርብ የነበረው ያልተመሳሰለ ሞዴሎችን በኔትዎርክ ውስጥ ያለውን አጠቃላይ ታሪክ ማስታወስ አለብን፡ ከተግባር ላይ የተመሰረተ ያልተመሳሰለ ንድፍ (TAP) ከመድረሱ በፊት ያልተመሳሰለ የፕሮግራሚንግ ጥለት (APP) ነበር። ስለ ዘዴዎች ነበር ጀመረየሚመለስ ነገር ያድርጉ የIAsync ውጤት እና ዘዴዎች መጨረሻDoSomething አስተናጋጁ እና ለእነዚህ ዓመታት ውርስ፣ የFromAsync ዘዴ በጣም ጥሩ ነው፣ ነገር ግን በጊዜ ሂደት፣ በ Event Based Asynchronous Pattern ተተካ (ኢ.ፒ.አይ.) ያልተመሳሰለው ክዋኔው ሲጠናቀቅ አንድ ክስተት ይነሳል ብሎ ገምቶ ነበር።

TaskCompletionSource በክስተቱ ሞዴል ዙሪያ የተገነቡ ተግባርን እና የቆዩ ኤፒአይዎችን ለመጠቅለል ፍጹም ነው። የሥራው ዋና ነገር እንደሚከተለው ነው-የዚህ ክፍል አንድ ነገር የተግባር አይነት የህዝብ ንብረት አለው, ሁኔታው ​​በ SetResult, SetException, ወዘተ በ TaskCompletionSource ክፍል ዘዴዎች ቁጥጥር ሊደረግበት ይችላል. ተጠባባቂው ኦፕሬተር በዚህ ተግባር ላይ በተተገበረባቸው ቦታዎች፣ ለተግባር ማጠናቀቂያ ምንጭ በተተገበረው ዘዴ ላይ በመመስረት በተለየ ሁኔታ ይፈጸማል ወይም ይወድቃል። አሁንም ግልጽ ካልሆነ፣ አንዳንድ የድሮ ኢኤፒ-ኤፒአይ 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 ማድረግ የሚችሉት የድሮ ኤፒአይዎችን መጠቅለል ብቻ አይደለም። ይህንን ክፍል መጠቀም ክሮች በማይያዙ ተግባራት ላይ የተለያዩ ኤፒአይዎችን የመንደፍ አስደሳች እድል ይከፍታል። እና ፍሰቱ, እንደምናስታውሰው, ውድ ሀብት ነው እና ቁጥራቸው የተገደበ ነው (በተለይም በ RAM መጠን). ይህ ገደብ ሲፈጠር ለማግኘት ቀላል ነው፣ ለምሳሌ የተጫነ የድር መተግበሪያን ውስብስብ የንግድ አመክንዮ። እንደ ሎንግ-ምርጫ ባሉ ዘዴዎች ትግበራ ላይ የምናገረውን አማራጮች እናስብ።

በአጭሩ ፣ የማታለያው ዋና ነገር ይህ ነው-በእሱ በኩል ስለተከሰቱ አንዳንድ ክስተቶች ከኤፒአይ መረጃ መቀበል ያስፈልግዎታል ፣ ኤፒአይ በሆነ ምክንያት ክስተቱን ሪፖርት ማድረግ አይችልም ፣ ግን ግዛቱን ብቻ መመለስ ይችላል። የዚህ ምሳሌ ከዌብሶኬት ጊዜ በፊት ወይም በሆነ ምክንያት ይህንን ቴክኖሎጂ ለመጠቀም በማይቻልበት ጊዜ በኤችቲቲፒ ላይ የተገነቡ ሁሉም ኤፒአይዎች ናቸው። ደንበኛው የኤችቲቲፒ አገልጋይ መጠየቅ ይችላል። የኤችቲቲፒ አገልጋይ ከደንበኛ ጋር ግንኙነትን በራሱ መጀመር አይችልም። ቀላል መፍትሄ አገልጋዩን በሰዓት ቆጣሪ ላይ ድምጽ መስጠት ነው ፣ ግን ይህ በአገልጋዩ ላይ ተጨማሪ ጭነት እና በአማካይ TimerInterval / 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ን ስለመጠቀም ማሰብ ትችላለህ።

የመልእክት ጥያቄ ሲደርስን በመዝገበ-ቃላቱ ውስጥ የተግባር ማጠናቀቂያ ምንጭን እንፈጥራለን እና እናስቀምጠዋለን እና ከዚያ መጀመሪያ ምን እንደሚፈጠር እንጠብቃለን-የተጠቀሰው የጊዜ ክፍተት ያበቃል ወይም መልእክት ደርሷል።

ValueTask፡ ለምን እና እንዴት

ያልተመሳሰለው/የመጠባበቅ መግለጫዎች፣ ልክ እንደ ምርት መመለሻ መግለጫ፣ ከስልቱ የስቴት ማሽን ያመነጫሉ፣ እና ይሄ አዲስ ነገር መፍጠር ነው፣ ሁልጊዜም አስፈላጊ አይደለም፣ ነገር ግን አልፎ አልፎ ችግር ሊፈጥር ይችላል። ይህ ጉዳይ በጣም ብዙ ጊዜ ተብሎ የሚጠራ ዘዴ ሊሆን ይችላል, እየተነጋገርን ያለነው በሴኮንድ በአስር እና በመቶ ሺዎች የሚቆጠሩ ጥሪዎች ነው. እንዲህ ዓይነቱ ዘዴ የተጻፈው በአብዛኛዎቹ ሁኔታዎች ሁሉንም የመጠባበቅ ዘዴዎችን በማለፍ ውጤቱን ይመልሳል ፣ ከዚያ NET ይህንን ለማመቻቸት መሳሪያ ይሰጣል - የቫልዩታስክ መዋቅር። ግልጽ ለማድረግ, የአጠቃቀም ምሳሌን ተመልከት: ብዙ ጊዜ የምንሄድበት መሸጎጫ አለ. በውስጡ አንዳንድ እሴቶች አሉ እና ከዚያ በቀላሉ እንመልሳቸዋለን፣ ካልሆነ፣ ከዚያ በኋላ ወደ አንዳንድ ቀርፋፋ 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);
}

በእርግጥ በዚህ ጉዳይ ላይ ጥሩው መፍትሔ የሙቅ-መንገዱን ማመቻቸት ማለትም ያለምንም አላስፈላጊ ምደባ ከመዝገበ-ቃላቱ ላይ ያለውን ዋጋ ማግኘት እና በጂ.ሲ.ሲ ላይ መጫን ነው ፣ በእነዚያ አልፎ አልፎ ወደ 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));
}

ይህንን የኮድ ቁርጥራጭ ጠለቅ ብለን እንመርምር-በመሸጎጫው ውስጥ ዋጋ ካለ, መዋቅርን እንፈጥራለን, አለበለዚያ እውነተኛው ስራ ትርጉም ባለው መልኩ ይጠቀለላል. የጥሪ ኮዱ ይህ ኮድ በየትኛው ዱካ ላይ እንደተፈጸመ ግድ የለውም፡ ValueTask፣ ከC# አገባብ አንፃር፣ በዚህ ጉዳይ ላይ ከመደበኛ ተግባር ጋር ተመሳሳይ ይሆናል።

የተግባር መርሐ ግብሮች፡ ተግባራትን የማስጀመር ስልቶችን ማስተዳደር

እኔ ከግምት የምፈልገው የሚቀጥለው ኤፒአይ ክፍል ነው። ተግባር መርሐግብር እና ተዋጽኦዎቹ። ቀደም ሲል TPL ተግባራትን በክሮች ውስጥ የማሰራጨት ስልቶችን የማስተዳደር ችሎታ እንዳለው አስቀድሜ ጠቅሻለሁ። እንደነዚህ ያሉት ስልቶች የተገለጹት በተግባር መርሐግብር ክፍል ወራሾች ውስጥ ነው። የሚያስፈልግዎ ማንኛውም ስልት ማለት ይቻላል በቤተ-መጽሐፍት ውስጥ ይገኛል። ParallelExtensionsExtrasበማይክሮሶፍት የተሰራ፣ ግን የ.NET አካል ያልሆነ፣ ግን እንደ ኑጌት ጥቅል የቀረበ። አንዳንዶቹን ባጭሩ እንመልከት፡-

  • CurrentThreadTask Scheduler - አሁን ባለው ክር ላይ ተግባራትን ያከናውናል
  • የተግባር ደረጃ የተግባር መርሐግብር የተወሰነ - በግንባታው ውስጥ ተቀባይነት ባለው መለኪያ N በአንድ ጊዜ የሚከናወኑ ተግባራትን ይገድባል
  • የታዘዘ ተግባር መርሐግብር - የተገደበ ConcurrencyLevelTaskScheduler(1) ተብሎ ይገለጻል፣ ስለዚህ ተግባሮቹ በቅደም ተከተል ይከናወናሉ።
  • የስራ መስረቅ ተግባር መርሐግብር - መሳሪያዎች ሼል-መስረቅ የተግባር ስርጭት አቀራረብ. እንደ እውነቱ ከሆነ, የተለየ Threadpool ነው. ችግሩን ይፈታል በ NET ThreadPool ውስጥ የማይንቀሳቀስ ክፍል ነው ፣ ለሁሉም አፕሊኬሽኖች አንዱ ፣ ይህ ማለት በአንድ የፕሮግራሙ ክፍል ውስጥ ከመጠን በላይ መጫኑ ወይም አላግባብ መጠቀሙ በሌላው ላይ የጎንዮሽ ጉዳቶችን ያስከትላል ማለት ነው። ከዚህም በላይ የእንደዚህ አይነት ጉድለቶች መንስኤ ምን እንደሆነ ለመረዳት እጅግ በጣም አስቸጋሪ ነው. ያ። የትሬድፑል አጠቃቀም ጠበኛ እና ሊተነበይ በማይችልባቸው የፕሮግራሙ ክፍሎች ውስጥ የተለየ WorkStealingTaskSchedulers መጠቀም ሊያስፈልግ ይችላል።
  • QueuedTask Scheduler - በቅድመ ወረፋ ደንቦች መሰረት ስራዎችን እንዲፈጽሙ ይፈቅድልዎታል
  • ThreadPerTask Scheduler - በእሱ ላይ ለሚተገበረው ለእያንዳንዱ ተግባር የተለየ ክር ይፈጥራል. ለመጨረስ ያልተጠበቀ ጊዜ ለሚወስዱ ተግባራት ጠቃሚ ሊሆን ይችላል.

ጥሩ ዝርዝር አለ ጽሑፍ በማይክሮሶፍት ብሎግ ላይ ስለ TaskSchedulers።

ከተግባሮች ጋር ለተያያዙ ነገሮች ሁሉ ምቹ ማረም ቪዥዋል ስቱዲዮ የተግባር መስኮት አለው። በዚህ መስኮት ውስጥ አሁን ያለውን የስራውን ሁኔታ ማየት እና አሁን ወደሚሰራው የኮድ መስመር መዝለል ይችላሉ.

.NET: ከብዙ-ክር እና ተመሳሳይነት ጋር ለመስራት የሚረዱ መሳሪያዎች. ክፍል 1

PLinq እና ትይዩ ክፍል

ከተግባሮች እና በ NET ውስጥ ከተነገሩት ነገሮች በተጨማሪ ሁለት ተጨማሪ አስደሳች መሳሪያዎች አሉ፡ PLinq(Linq2Parallel) እና Parallel class። የመጀመሪያው ሁሉንም የሊንክ ስራዎች በበርካታ ክሮች ላይ በትይዩ ለማስኬድ ቃል ገብቷል. የክሮች ብዛት በ WithDegreeOfParallelism ቅጥያ ዘዴ ሊዋቀር ይችላል። እንደ አለመታደል ሆኖ ብዙውን ጊዜ PLinq በነባሪ ሁኔታው ​​ስለ የውሂብ ምንጭዎ ውስጣዊ ነገሮች በቂ መረጃ አይኖረውም ፣ በሌላ በኩል ደግሞ የመሞከር ዋጋ በጣም ዝቅተኛ ነው-ከዚህ በፊት ወደ AsParallel ዘዴ መደወል ያስፈልግዎታል። የሊንክ ዘዴ ሰንሰለት እና የአፈፃፀም ሙከራዎችን ያከናውኑ. በተጨማሪም፣ ስለ የውሂብ ምንጭዎ ተፈጥሮ ተጨማሪ መረጃ ክፍልፍሎች ዘዴን በመጠቀም ለ PLinq ማስተላለፍ ይቻላል። የበለጠ ማንበብ ትችላለህ እዚህ и እዚህ.

የስታቲክ ትይዩ ክፍል በ Foreach ስብስብ በትይዩ ለመድገም ፣ ፎር loopን ለማስፈፀም እና በ Invoke ትይዩ ውስጥ ብዙ ተወካዮችን የማስፈጸሚያ ዘዴዎችን ይሰጣል። ስሌቶቹ ከመጠናቀቁ በፊት የአሁኑ ክር አፈፃፀም ይቆማል. ParallelOptionsን እንደ የመጨረሻው ነጋሪ እሴት በማለፍ የክሮች ብዛት ሊዋቀር ይችላል። እንዲሁም አማራጮችን በመጠቀም TaskScheduler እና CancellationTokenን መግለጽ ይችላሉ።

ግኝቶች

ይህን ጽሁፍ መጻፍ የጀመርኩት ከሪፖርቴ ይዘት እና ከሱ በኋላ በስራዬ የሰበሰብኩትን መረጃ መሰረት በማድረግ ብዙ ይሆናል ብዬ አልጠበኩም ነበር። አሁን እኔ ይህን ጽሁፍ የምጽፍበት የጽሁፍ አርታኢ 15ኛው ገጽ እንደሄደ ሲነግረኝ መካከለኛ ውጤቶቹን አጠቃልላለሁ። ሌሎች ብልሃቶች፣ ኤፒአይዎች፣ የእይታ መሳሪያዎች እና ወጥመዶች በሚቀጥለው ርዕስ ውስጥ ይሸፈናሉ።

መደምደሚያ-

  • የዘመናዊ ፒሲዎችን ሃብቶች ለመጠቀም ከክር, ተመሳሳይነት እና ትይዩ ጋር ለመስራት መሳሪያዎችን ማወቅ አለብዎት.
  • ለዚህ ዓላማ በ NET ውስጥ ብዙ የተለያዩ መሳሪያዎች አሉ.
  • ሁሉም በአንድ ጊዜ አይታዩም, ምክንያቱም ብዙ ጊዜ ቅርሶችን ማግኘት ይችላሉ, ሆኖም ግን, ያለ ብዙ ጥረት የድሮ ኤፒአይዎችን ለመለወጥ መንገዶች አሉ.
  • በ NET ውስጥ ያለው ክር በ Thread እና ThreadPool ክፍሎች ይወከላል።
  • Thread.Abort, Thread.Interrupt, TerminateThread Win32 API ተግባራት አደገኛ ናቸው እና አይመከርም. በምትኩ፣ የCancelationTokens ዘዴን መጠቀም የተሻለ ነው።
  • ፍሰቱ ጠቃሚ ሃብት ነው, ቁጥራቸው የተገደበ ነው. ክሮች ክስተቶችን በመጠበቅ የተጠመዱበትን ሁኔታዎች ያስወግዱ። ይህንን ለማድረግ የ TaskCompletionSource ክፍልን ለመጠቀም ምቹ ነው.
  • በጣም ኃይለኛ እና የላቁ የ .NET መሳሪያዎች ከኮንፈረንስ እና ተመሳሳይነት ጋር የተያያዙ ተግባራት ናቸው.
  • c# አስምር/የመጠባበቅ መግለጫዎች መጠበቅን አለማገድ የሚለውን ጽንሰ ሃሳብ ተግባራዊ ያደርጋሉ
  • TaskScheduler ተዋጽኦ ክፍሎችን በመጠቀም በክር መካከል የተግባር ስርጭትን መቆጣጠር ትችላለህ
  • የValueTask መዋቅር ሙቅ መንገዶችን እና የማስታወስ-ትራፊክን ለማመቻቸት ጠቃሚ ሊሆን ይችላል።
  • የ Visual Studio የተግባር እና ክሮች መስኮቶች ባለብዙ-ክር ወይም ያልተመሳሰል ኮድ ለማረም ብዙ ጠቃሚ መረጃዎችን ይሰጣሉ።
  • PLinq ጥሩ መሣሪያ ነው፣ ነገር ግን ሾለ የውሂብ ምንጭዎ በቂ መረጃ ላይኖረው ይችላል፣ ነገር ግን ይህ የመከፋፈል ዘዴን በመጠቀም ሊስተካከል ይችላል
  • ይቀጥላል…

ምንጭ: hab.com

አስተያየት ያክሉ