.NET: ملٽي ٿريڊنگ ۽ اسينڪروني سان ڪم ڪرڻ جا اوزار. حصو 1

مان اصل مضمون حبر تي شايع ڪري رهيو آهيان، جنهن جو ترجمو ڪارپوريٽ ۾ پوسٽ ڪيو ويو آهي بلاگ پوسٽ.

ھتي ۽ ھاڻي نتيجن جو انتظار ڪرڻ کان سواءِ، ڪنھن ڪم کي هم وقت سازيءَ سان ڪرڻ جي ضرورت، يا وڏي ڪم کي ڪيترن ئي يونٽن ۾ ورهائڻ جي ضرورت، ڪمپيوٽرن جي اچڻ کان اڳ موجود ھئي. انهن جي اچڻ سان، اها ضرورت تمام گهڻي ٿي وئي. هاڻي، 2019 ۾، مان هي مضمون ٽائيپ ڪري رهيو آهيان هڪ ليپ ٽاپ تي هڪ 8-ڪور Intel ڪور پروسيسر سان، جنهن تي هڪ سئو کان وڌيڪ پروسيس متوازي طور تي هلندا آهن، ۽ اڃا به وڌيڪ موضوع. ويجھو، ھڪڙو ٿورڙو جھليل فون آھي، جيڪو ڪجھ سال اڳ خريد ڪيو ويو آھي، ان ۾ بورڊ تي 8-ڪور پروسيسر آھي. موضوعي وسيلا مضمونن ۽ وڊيوز سان ڀريل آهن جتي انهن جا ليکڪ هن سال جي پرچم بردار اسمارٽ فونز جي تعريف ڪندا آهن جيڪي 16-ڪور پروسيسرز جي خاصيت رکن ٿا. MS Azure هڪ ورچوئل مشين فراهم ڪري ٿو 20 ڪور پروسيسر ۽ 128 TB ريم سان $2 / ڪلاڪ کان گهٽ. بدقسمتي سان، وڌ کان وڌ ڪڍڻ ۽ هن طاقت کي استعمال ڪرڻ ناممڪن آهي بغير موضوعن جي رابطي کي منظم ڪرڻ جي قابل.

اصطلاحات

عمل - OS اعتراض، الڳ ٿيل پتي جي جاء، موضوعن تي مشتمل آهي.
ٿلهو - هڪ OS اعتراض، عمل جو ننڍڙو يونٽ، هڪ عمل جو حصو، ٿريڊز هڪ پروسيس ۾ پاڻ ۾ ميموري ۽ ٻيا وسيلا حصيداري ڪندا آهن.
گهڻن ڪم لاءِ - OS ملڪيت، ڪيترن ئي عملن کي گڏ ڪرڻ جي صلاحيت
ملٽي ڪور - پروسيسر جي ملڪيت، ڊيٽا پروسيسنگ لاء ڪيترن ئي ڪور استعمال ڪرڻ جي صلاحيت
ملٽي پروسيسنگ - ڪمپيوٽر جي ملڪيت، ڪيترن ئي پروسيسرز سان گڏ ڪم ڪرڻ جي صلاحيت جسماني طور تي
ملٽي ٽريڊنگ - هڪ عمل جي ملڪيت، ڊيٽا پروسيسنگ کي ڪيترن ئي موضوعن ۾ ورهائڻ جي صلاحيت.
متوازيت - وقت جي في يونٽ جي جسماني طور تي ڪيترن ئي عملن کي انجام ڏيڻ
هم وقت سازي - هن پروسيسنگ جي مڪمل ٿيڻ جو انتظار ڪرڻ کان سواء، عمل جي نتيجي تي عمل ڪري سگهجي ٿو.

استعارا

سڀئي وصفون سٺيون نه آهن ۽ ڪجهه اضافي وضاحت جي ضرورت آهي، تنهنڪري مان هڪ استعارا شامل ڪندس ناشتي کي پچائڻ بابت رسمي طور تي متعارف ٿيل اصطلاحن ۾. هن استعاري ۾ ناشتو پچائڻ هڪ عمل آهي.

صبح جو ناشتو تيار ڪندي آئون (سي پي يومان باورچی خانه ۾ اچان ٿو (ڪمپيوٽر). مون وٽ 2 هٿ آهن (cores). باورچی خانه ۾ ڪيترائي ڊوائيس آھن (IO): تندور، ڪيٽل، ٽوسٽر، فرج. مان گيس آن ڪري، ان تي فرائينگ پين رکان ٿو ۽ ان جي گرم ٿيڻ جو انتظار ڪرڻ بغير ان ۾ تيل وجھي ٿو.هم وقت سازي، غير بلاڪنگ-IO-Wat)، مان انڊا ڪڍي فرج مان ڪڍان ٿو ۽ انهن کي پليٽ ۾ ٽوڙي پوءِ انهن کي هڪ هٿ سان ماريو (موضوع نمبر 1)، ۽ ٻيو (موضوع نمبر 2) پليٽ کي پڪڙڻ (شيئر ريسورس). ھاڻي مان ڪيٽل چالو ڪرڻ چاھيان ٿو، پر مون وٽ ڪافي ھٿ نه آھن (تاري جي بک) هن عرصي دوران، فرائينگ پين کي گرم ڪري ٿو (نتيجي کي پروسيس ڪندي) جنهن ۾ مون کي وجھي ڇڏيو آهي. مان ڪيٽلي تائين پهچان ٿو ۽ ان کي چالو ڪريان ٿو ۽ بيوقوفيءَ سان ان ۾ پاڻيءَ کي اُبلندي ڏسان ٿو (بلاڪ ڪرڻ- IO- انتظار ڪريو)، جيتوڻيڪ ان عرصي دوران هو پليٽ کي ڌوئي سگهيو ٿي، جتي هن آمليٽ کي ڇڪايو هو.

مون صرف 2 ھٿن سان آمليٽ تيار ڪيو، ۽ مون وٽ وڌيڪ ڪونھي، پر ساڳئي وقت، آمليٽ کي چيڀاٽڻ وقت، ھڪ ئي وقت 3 آپريشن ڪيا ويا: آمليٽ کي چيڀاٽڻ، پليٽ ھلائڻ، فرائينگ پين کي گرم ڪرڻ سي پي يو ڪمپيوٽر جو تيز ترين حصو آهي، IO اهو آهي جيڪو گهڻو ڪري هر شي سست ٿي ويندو آهي، تنهنڪري اڪثر ڪري هڪ مؤثر حل اهو آهي ته IO کان ڊيٽا حاصل ڪرڻ دوران سي پي يو تي قبضو ڪيو وڃي.

استعارا جاري رکڻ:

  • جيڪڏهن آمليٽ تيار ڪرڻ جي عمل ۾، آئون به ڪپڙا تبديل ڪرڻ جي ڪوشش ڪندس، اهو هڪ مثالي ملٽي ٽاسڪنگ جو هوندو. هڪ اهم nuance: ڪمپيوٽرن هن تي تمام گهڻو بهتر آهن ماڻهن جي ڀيٽ ۾.
  • هڪ باورچی خانه ڪيترن ئي شيف سان، مثال طور هڪ ريسٽورنٽ ۾ - هڪ ملٽي ڪور ڪمپيوٽر.
  • هڪ شاپنگ سينٽر ۾ فوڊ ڪورٽ ۾ ڪيترائي ريسٽورنٽ - ڊيٽا سينٽر

.NET اوزار

.NET موضوعن سان ڪم ڪرڻ ۾ سٺو آهي، جيئن ٻين ڪيترن ئي شين سان. هر نئين ورزن سان، اهو انهن سان ڪم ڪرڻ لاءِ وڌيڪ ۽ وڌيڪ نوان اوزار متعارف ڪرائيندو آهي، او ايس ٿريڊز تي تجريد جا نوان پرت. جڏهن تجريد جي تعمير سان ڪم ڪري رهيا آهن، فريم ورڪ ڊولپرز هڪ طريقو استعمال ڪن ٿا جيڪو موقعو ڇڏي ٿو، جڏهن هڪ اعلي سطحي تجريد استعمال ڪندي، هيٺ هڪ يا وڌيڪ سطح هيٺ وڃڻ لاء. گهڻو ڪري اهو ضروري ناهي، حقيقت ۾ اهو هڪ شاٽگن سان پنهنجي پيرن ۾ فائرنگ ڪرڻ جو دروازو کوليندو آهي، پر ڪڏهن ڪڏهن، نادر ڪيسن ۾، اهو مسئلو حل ڪرڻ جو واحد طريقو ٿي سگهي ٿو جيڪو موجوده تجريد جي سطح تي حل نه ڪيو ويو آهي. .

اوزارن مان، منهنجو مطلب آهي فريم ورڪ ۽ ٽئين پارٽي پيڪيجز پاران مهيا ڪيل ٻئي ايپليڪيشن پروگرامنگ انٽرفيس (APIs)، گڏوگڏ سڄو سافٽ ويئر حل جيڪي ملٽي ٿريڊ ڪوڊ سان لاڳاپيل ڪنهن به مسئلن جي ڳولا کي آسان بڻائين ٿا.

هڪ سلسلي جي شروعات

ٿريڊ ڪلاس .NET ۾ ٿريڊن سان ڪم ڪرڻ لاءِ سڀ کان بنيادي ڪلاس آھي. تعمير ڪندڙ ٻن نمائندن مان هڪ کي قبول ڪري ٿو:

  • ThreadStart - ڪوبه پيرا ميٽر نه
  • ParametrizedThreadStart - ھڪڙي قسم جي اعتراض سان.

نمائندي کي نئين ٺاهيل سلسلي ۾ عمل ڪيو ويندو شروع جي طريقي کي ڪال ڪرڻ کان پوء، جيڪڏهن هڪ نمائندو ParametrizedThreadStart قسم جي تعمير ڪندڙ کي منظور ڪيو ويو، پوء هڪ اعتراض کي شروع ڪرڻ جي طريقي سان پاس ڪيو وڃي. هي ميکانيزم ڪنهن به مقامي معلومات کي وهڪرو ڏانهن منتقل ڪرڻ جي ضرورت آهي. اها ڳالهه نوٽ ڪرڻ جي قابل آهي ته هڪ ڌاڳو ٺاهڻ هڪ قيمتي آپريشن آهي، ۽ ڌاڳو پاڻ هڪ ڳري اعتراض آهي، گهٽ ۾ گهٽ ڇاڪاڻ ته اهو اسٽيڪ تي 1MB ميموري مختص ڪري ٿو ۽ OS API سان رابطي جي ضرورت آهي.

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

ThreadPool ڪلاس پول جي تصور جي نمائندگي ڪري ٿو. .NET ۾، ٿريڊ پول انجنيئرنگ جو هڪ ٽڪرو آهي، ۽ Microsoft تي ڊولپرز تمام گهڻي ڪوشش ڪئي آهي انهي کي يقيني بڻائڻ لاءِ ته اهو مختلف حالتن ۾ بهتر نموني ڪم ڪري.

عام تصور:

جڏهن کان ايپليڪيشن شروع ٿئي ٿي، اهو پس منظر ۾ رزرو ۾ ڪيترن ئي موضوعن کي ٺاهي ٿو ۽ انهن کي استعمال ڪرڻ جي صلاحيت فراهم ڪري ٿو. جيڪڏهن سلسلا اڪثر ۽ وڏي تعداد ۾ استعمال ڪيا وڃن ٿا، پول ڪالر جي ضرورتن کي پورو ڪرڻ لاءِ وڌندو آهي. جڏهن صحيح وقت تي تلاءَ ۾ ڪي به آزاد موضوع نه هوندا، ته اهو يا ته ڪنهن هڪ سلسلي جي واپسي جو انتظار ڪندو، يا هڪ نئون ٺاهيندو. اهو هن ريت آهي ته ٿريڊ پول ڪجهه مختصر مدت جي عملن لاءِ بهترين آهي ۽ آپريشن لاءِ ناقص موزون آهي جيڪي ايپليڪيشن جي پوري آپريشن دوران سروسز طور هلن ٿيون.

پول مان ٿريڊ استعمال ڪرڻ لاءِ، اتي ھڪڙو QueueUserWorkItem طريقو آھي جيڪو WaitCallback قسم جي نمائندي کي قبول ڪري ٿو، جنھن جي ساڳي نشاني آھي ParametrizedThreadStart، ۽ ان کي پاس ڪيل پيراميٽر ساڳيو ڪم سرانجام ڏئي ٿو.

ThreadPool.QueueUserWorkItem(...);

گهٽ ڄاڻايل ٿريڊ پول طريقو RegisterWaitForSingleObject غير بلاڪنگ IO آپريشنز کي منظم ڪرڻ لاءِ استعمال ڪيو ويندو آهي. هن طريقي سان منظور ٿيل نمائندو سڏيو ويندو جڏهن WaitHandle طريقي سان منظور ڪيو ويو آهي "رليز ٿيل".

ThreadPool.RegisterWaitForSingleObject(...)

.NET وٽ هڪ ٿريڊ ٽائمر آهي ۽ اهو WinForms/WPF ٽائمرز کان مختلف آهي ته ان جو هينڊلر پول مان ورتل ٿريڊ تي سڏبو.

System.Threading.Timer

اتي پڻ ھڪڙو غير معمولي طريقو آھي ھڪڙو نمائندو موڪلڻ لاءِ عمل درآمد لاءِ پول مان ھڪڙي سلسلي ڏانھن - BeginInvoke طريقو.

DelegateInstance.BeginInvoke

مان مختصر طور تي ھن فنڪشن تي رھڻ چاھيان ٿو جنھن کي مٿين طريقن مان ڪيترائي سڏي سگھجن ٿا - CreateThread from Kernel32.dll Win32 API. اتي ھڪڙو طريقو آھي، ٻاھرين طريقن جي ميکانيزم جي مھرباني، ھن فنڪشن کي سڏڻ لاء. مون اهڙي ڪال کي صرف هڪ ڀيرو ڏٺو آهي هڪ خوفناڪ مثال ۾ ورثي واري ڪوڊ، ۽ ليکڪ جي حوصلا افزائي جيڪو اهو ڪيو هو اڃا تائين مون لاء هڪ راز رهي ٿو.

Kernel32.dll CreateThread

ڏسڻ ۽ ڊيبگنگ سلسلي

توھان جا ٺاھيل موضوع، سڀ ٽئين پارٽي جا حصا، ۽ .NET پول کي ڏسي سگھجي ٿو Visual Studio جي Threads ونڊو ۾. هي ونڊو صرف ان سلسلي جي معلومات ڏيکاريندي جڏهن ايپليڪيشن ڊيبگ ۽ بريڪ موڊ ۾ هجي. هتي توهان آساني سان هر سلسلي جي اسٽيڪ جا نالا ۽ ترجيحات ڏسي سگهو ٿا، ۽ ڊيبگنگ کي هڪ مخصوص سلسلي ۾ تبديل ڪري سگهو ٿا. ٿريڊ ڪلاس جي ترجيحي ملڪيت کي استعمال ڪندي، توھان ھڪڙي سلسلي جي ترجيح مقرر ڪري سگھو ٿا، جنھن کي OC ۽ CLR ھڪڙي سفارش جي طور تي سمجھندا آھن جڏھن پروسيسر جي وقت کي موضوعن جي وچ ۾ ورهايو ويندو.

.NET: ملٽي ٿريڊنگ ۽ اسينڪروني سان ڪم ڪرڻ جا اوزار. حصو 1

ٽاسڪ متوازي لائبريري

ٽاسڪ متوازي لائبريري (TPL) .NET 4.0 ۾ متعارف ڪرايو ويو. ھاڻي اھو آھي معياري ۽ بنيادي اوزار asynchrony سان ڪم ڪرڻ لاءِ. ڪو به ڪوڊ جيڪو پراڻي طريقي سان استعمال ڪري ٿو ورثي سمجهي وڃي ٿو. TPL جو بنيادي يونٽ System.Threading.Tasks namespace مان ٽاسڪ ڪلاس آهي. هڪ ڪم هڪ موضوع تي هڪ خلاصو آهي. C# ٻوليءَ جي نئين ورزن سان، اسان کي ٽاسڪ سان ڪم ڪرڻ جو هڪ خوبصورت طريقو مليو آهي - async/await operators. انهن تصورن اهو ممڪن بڻايو ته غير هم وقتي ڪوڊ لکڻ ڄڻ ته اهو سادو ۽ هم وقت ساز هو، اهو انهن ماڻهن لاءِ به ممڪن بڻيو جيڪي ٿريڊن جي اندروني ڪم جي ٿوري سمجھ رکندڙ آهن اهي ايپليڪيشنون لکڻ لاءِ جيڪي انهن کي استعمال ڪن ٿيون، ايپليڪيشنون جيڪي ڊگها آپريشن ڪرڻ وقت منجمد نه ٿيون ٿين. async/await استعمال ڪرڻ هڪ يا ڪيترن ئي مضمونن لاءِ هڪ موضوع آهي، پر مان ڪوشش ڪندس ته ان جو خلاصو چند جملن ۾:

  • async ٽاسڪ يا باطل موٽڻ واري طريقي جو هڪ ترميمي آهي
  • ۽ انتظار هڪ غير بلاڪ ڪرڻ وارو ٽاسڪ انتظار ڪندڙ آپريٽر آهي.

هڪ ڀيرو ٻيهر: انتظار ڪندڙ آپريٽر، عام صورت ۾ (استثناء موجود آهن)، جاري ڪندو موجوده ٿريڊ کي جاري ڪرڻ جي عمل کي، ۽ جڏهن ٽاسڪ ان جي عمل کي ختم ڪري ٿو، ۽ موضوع (حقيقت ۾، اهو وڌيڪ صحيح ٿيندو ته اهو حوالو چوڻ وڌيڪ صحيح آهي. ، پر انهي تي وڌيڪ بعد ۾) طريقي تي عمل جاري رکندو. .NET جي اندر، هي ميکانيزم ساڳئي طريقي سان لاڳو ڪيو ويندو آهي جيئن پيداوار جي واپسي، جڏهن لکت وارو طريقو هڪ مڪمل ڪلاس ۾ تبديل ٿي ويندو آهي، جيڪو هڪ رياستي مشين آهي ۽ انهن رياستن جي لحاظ کان الڳ الڳ حصن ۾ ڪم ڪري سگهجي ٿو. ڪو به دلچسپي رکندڙ ماڻهو asynс/await استعمال ڪندي ڪو به سادو ڪوڊ لکي سگهي ٿو، Compiler Generated Code enabled سان 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 - مطلب ته اھو بھتر ھوندو ته عمل درآمد لاءِ موڪليا ويا ڪمن کي اڳي ئي اڳ ۾ جيڪي بعد ۾ موڪليا ويا آھن. پر اهو صرف هڪ سفارش آهي ۽ نتيجن جي ضمانت نه آهي.

ٻيو پيٽرولر طريقو ڏانهن گذريو آهي CancellationToken. هڪ آپريشن شروع ٿيڻ کان پوءِ ان جي منسوخي کي صحيح طريقي سان سنڀالڻ لاءِ، جيڪو ڪوڊ جاري ڪيو پيو وڃي، اهو لازمي طور تي چيڪن سان ڀريو وڃي ٿو CancellationToken اسٽيٽ لاءِ. جيڪڏهن ڪي به چيڪ نه آهن، ته پوء منسوخ ڪرڻ جو طريقو سڏيو ويندو آهي CancellationTokenSource اعتراض تي عمل کي روڪڻ جي قابل هوندو صرف ان جي شروع ٿيڻ کان اڳ.

آخري پيٽرولر ٽائيپ شيڊولر جو هڪ شيڊولر اعتراض آهي. هي طبقو ۽ ان جو اولاد ٽاسڪ کي ورهائڻ لاءِ حڪمت عملين تي ڪنٽرول ڪرڻ لاءِ ٺاهيو ويو آهي ڊفالٽ طور، ٽاسڪ کي پول مان بي ترتيب واري سلسلي تي عمل ڪيو ويندو.

انتظار آپريٽر ٺاهيل ٽاسڪ تي لاڳو ڪيو ويو آهي، جنهن جو مطلب آهي ڪوڊ جيڪو ان کان پوء لکيو ويو آهي، جيڪڏهن ڪو آهي، ته ساڳئي حوالي سان عمل ڪيو ويندو (اڪثر ڪري هن جو مطلب ساڳئي موضوع تي) ڪوڊ جي انتظار کان اڳ.

طريقو async void جي طور تي نشان لڳايو ويو آهي، جنهن جو مطلب آهي ته اهو انتظار آپريٽر استعمال ڪري سگهي ٿو، پر ڪالنگ ڪوڊ عملدرآمد لاء انتظار ڪرڻ جي قابل نه هوندو. جيڪڏهن اهڙي خاصيت ضروري آهي، ته پوء اهو طريقو لازمي آهي ٽاسڪ. async void نشان لڳل طريقا ڪافي عام آھن: ضابطي جي طور تي، اھي ايونٽ ھينڊلر يا ٻيا طريقا آھن جيڪي ڪم ڪن ٿا باھ تي ۽ اصول کي وساريو. جيڪڏهن توهان کي نه رڳو اهو موقعو ڏيڻ گهرجي ته عمل جي آخر تائين انتظار ڪريو، پر نتيجو پڻ واپس ڏيو، پوء توهان کي ٽاسڪ استعمال ڪرڻ جي ضرورت آهي.

انهي ٽاسڪ تي جيڪو 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/await استعمال ڪرڻ وقت غير هم وقتي ڪوڊ ۾ غلطيون سنڀالڻ تمام آسان آهن - اهي ساڳيو ئي عمل ڪن ٿا ڄڻ ته ڪوڊ هم وقت هو. جڏهن ته جيڪڏهن اسان هڪ ٽاسڪ لاءِ هم وقت ساز انتظار خارج ڪرڻ جو عمل لاڳو ڪريون ٿا، ته اصل استثنا AggregateException ۾ بدلجي وڃي ٿو، يعني. استثنا کي سنڀالڻ لاءِ، توهان کي InnerException قسم جو جائزو وٺڻو پوندو ۽ هڪ if chain پنهنجي پاڻ کي هڪ ڪيچ بلاڪ جي اندر لکڻو پوندو يا ڪيچ بلاڪ جي زنجير جي بدران، ڪيچ بلاڪ کي استعمال ڪريو جيڪو C# دنيا ۾ وڌيڪ واقف آهي.

ٽيون ۽ آخري مثال به ساڳئي سبب جي ڪري خراب نشان لڳل آهن ۽ اهي سڀئي ساڳيا مسئلا آهن.

جڏهن ڪو به ۽ جڏهن سڀ طريقا ٽاسڪ جي هڪ گروپ جي انتظار لاءِ انتهائي آسان آهن؛ اهي ٽاسڪ جي هڪ گروهه کي هڪ ۾ ويڙهي ڇڏيندا آهن، جيڪو يا ته فائر ڪندو جڏهن گروپ مان هڪ ٽاسڪ پهريون ڀيرو شروع ڪيو ويندو، يا جڏهن انهن سڀني کي مڪمل ڪيو ويندو.

تارن کي روڪڻ

مختلف سببن جي ڪري، اهو ضروري ٿي سگھي ٿو ته وهڪري کي روڪڻ کان پوء ان کي شروع ڪيو وڃي. هن کي ڪرڻ جا ڪيترائي طريقا آهن. ٿريڊ ڪلاس جا ٻه مناسب نالا طريقا آهن: ايبٽ и سگو. پهرين هڪ انتهائي استعمال لاء سفارش نه آهي، ڇاڪاڻ ته ڪنهن به بي ترتيب واري لمحي تي سڏڻ کان پوء، ڪنهن به هدايت جي پروسيسنگ دوران، هڪ استثنا اڇلايو ويندو ThreadAbortedException. توهان کي توقع ناهي ته اهڙي استثنا کي اڇلايو وڃي جڏهن ڪنهن به انٽيجر متغير کي وڌايو وڃي، صحيح؟ ۽ جڏهن هن طريقي کي استعمال ڪندي، اهو هڪ بلڪل حقيقي صورتحال آهي. جيڪڏهن توهان CLR کي ڪوڊ جي هڪ خاص حصي ۾ اهڙي استثنا پيدا ڪرڻ کان روڪڻ جي ضرورت آهي، ته توهان ان کي ڪالن ۾ لپي سگهو ٿا Thread.BeginCriticalRegion, Thread.EndCriticalRegion. آخرڪار بلاڪ ۾ لکيل ڪو به ڪوڊ اهڙي ڪالن ۾ لپي ويو آهي. انهي سبب لاء، فريم ورڪ ڪوڊ جي کوٽائي ۾ توهان هڪ خالي ڪوشش سان بلاڪ ڳولي سگهو ٿا، پر آخرڪار خالي نه. Microsoft هن طريقي کي ايترو ته حوصلا افزائي ڪري ٿو جو انهن ان کي .net ڪور ۾ شامل نه ڪيو آهي.

مداخلت جو طريقو وڌيڪ اڳڪٿي سان ڪم ڪري ٿو. اهو هڪ استثنا سان سلسلي ۾ مداخلت ڪري سگهي ٿو ThreadInterruptedException صرف انهن لمحن دوران جڏهن موضوع هڪ انتظار جي حالت ۾ آهي. اھو ھن حالت ۾ داخل ٿئي ٿو پھانسي دوران انتظار ڪرڻ دوران WaitHandle، تالا، يا Thread.Sleep کي ڪال ڪرڻ کان پوء.

مٿي بيان ڪيل ٻئي اختيار خراب آهن انهن جي غير متوقع هجڻ جي ڪري. حل هڪ ساخت کي استعمال ڪرڻ آهي منسوخي ٽوڪن ۽ ڪلاس منسوخي ٽوڪن جو ذريعو. نقطو هي آهي: CancellationTokenSource ڪلاس جو هڪ مثال ٺاهيو ويو آهي ۽ صرف اهو جيڪو ان جو مالڪ آهي اهو طريقو ڪال ڪندي آپريشن کي روڪي سگهي ٿو. رد. صرف CancellationToken پاڻ کي آپريشن ڏانهن منتقل ڪيو ويو آهي. CancelationToken جا مالڪ پاڻ آپريشن کي منسوخ نٿا ڪري سگھن، پر صرف چيڪ ڪري سگھن ٿا ته ڇا آپريشن منسوخ ڪيو ويو آھي. هن لاءِ هڪ Boolean ملڪيت آهي منسوخ ڪرڻ جي درخواست ڪئي وئي آهي ۽ طريقو ThrowIfCancelRequested. بعد ۾ هڪ استثنا اڇلائي ڇڏيندو TaskCancelledException جيڪڏهن منسوخي جو طريقو سڏيو ويو هو CancellationToken مثال طور parroted تي. ۽ اهو طريقو آهي جيڪو آئون استعمال ڪرڻ جي صلاح ڪريان ٿو. هي اڳوڻن اختيارن جي ڀيٽ ۾ هڪ بهتري آهي جنهن تي مڪمل ڪنٽرول حاصل ڪرڻ سان ڪهڙي نقطي تي هڪ استثنا آپريشن کي ختم ڪري سگهجي ٿو.

هڪ سلسلي کي روڪڻ لاء سڀ کان وڌيڪ ظالمانه اختيار Win32 API TerminateThread فنڪشن کي سڏڻ آهي. هن فنڪشن کي سڏڻ کان پوءِ CLR جو رويو غير متوقع ٿي سگهي ٿو. MSDN تي هن فنڪشن بابت هيٺ ڏنل لکيو ويو آهي: "TerminateThread هڪ خطرناڪ فنڪشن آهي جيڪو صرف انتهائي ڪيسن ۾ استعمال ٿيڻ گهرجي. "

ورثي API کي ٽاسڪ جي بنياد تي FromAsync طريقي سان تبديل ڪرڻ

جيڪڏھن توھان ڪافي خوش قسمت آھيو ھڪڙي منصوبي تي ڪم ڪرڻ لاءِ جيڪو ٽاسڪ متعارف ڪرائڻ کان پوءِ شروع ڪيو ويو ۽ گھڻن ڊولپرز لاءِ خاموش خوفناڪ ٿيڻ جو سبب بڻيو، پوءِ توھان کي گھڻي پراڻي APIs سان معاملو ڪرڻ جي ضرورت نه پوندي، ٻئي ٽئين پارٽي وارا ۽ اھي توھان جي ٽيم. ماضي ۾ تشدد ڪيو آهي. خوش قسمت، .NET فريم ورڪ ٽيم اسان جو خيال رکيو، جيتوڻيڪ شايد مقصد پاڻ کي سنڀالڻ هو. جيئن ته ٿي سگهي ٿو، .NET وٽ ڪيترائي اوزار آهن بغير درد جي بدلي ڪوڊ کي پراڻي اسيڪرونس پروگرامنگ طريقن ۾ لکيل نئين هڪ ڏانهن. انهن مان هڪ آهي FromAsync جو طريقو TaskFactory. هيٺ ڏنل ڪوڊ مثال ۾، مان WebRequest ڪلاس جي پراڻي async طريقن کي لفاف ڪريان ٿو ٽاسڪ ۾ هن طريقي سان استعمال ڪندي.

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

اهو صرف هڪ مثال آهي ۽ توهان کي ممڪن ناهي ته اهو تعمير ٿيل قسمن سان ڪرڻو پوندو، پر ڪو به پراڻو پروجيڪٽ صرف BeginDoSomething طريقن سان ملندو آهي جيڪي IAsyncResult ۽ EndDoSomething طريقن کي واپس ڪن ٿا جيڪي ان کي وصول ڪن ٿا.

TaskCompletionSource ڪلاس استعمال ڪندي Legacy API کي Task Based ۾ تبديل ڪريو

غور ڪرڻ لاء هڪ ٻيو اهم اوزار ڪلاس آهي TaskCompletionSource. ڪمن، مقصد ۽ عمل جي اصولن جي لحاظ کان، اھو ٿي سگھي ٿو ڪنھن حد تائين RegisterWaitForSingleObject طريقي جي ThreadPool طبقي جي، جنھن بابت مون مٿي لکيو آھي. هن ڪلاس کي استعمال ڪندي، توهان آساني سان ۽ آسانيءَ سان پراڻا هم وقت ساز APIs ٽاسڪ ۾ لپي سگهو ٿا.

توهان چوندا ته مان انهن مقصدن لاءِ ارادو ڪيل TaskFactory ڪلاس جي FromAsync طريقي بابت اڳ ۾ ئي ڳالهائي چڪو آهيان. هتي اسان کي .net ۾ اسيئنڪرونس ماڊلز جي ترقيءَ جي پوري تاريخ ياد رکڻي پوندي جيڪا Microsoft گذريل 15 سالن ۾ پيش ڪئي آهي: ٽاسڪ بيسڊ اسينڪرونس پيٽرن (TAP) کان اڳ، اتي موجود هو Asynchronous Programming Pattern (APP)، جيڪو طريقن جي باري ۾ هو شروعڪجھھ موٽڻ IAsyncResult ۽ طريقا آخر ۾DoSomething جيڪو ان کي قبول ڪري ٿو ۽ انهن سالن جي ورثي لاءِ FromAsync طريقو بلڪل ڀرپور آهي، پر وقت گذرڻ سان گڏ، ان کي تبديل ڪيو ويو ايونٽ بيسڊ اسينڪرونس پيٽرن (اي اي پي جي)، جنهن فرض ڪيو ته هڪ واقعو اٿاريو ويندو جڏهن غير مطابقت واري آپريشن مڪمل ٿي ويندي.

TaskCompletionSource ايونٽ ماڊل جي چوڌاري ٺهيل ٽاسڪ ۽ ورثي APIs کي لڪائڻ لاءِ مڪمل آهي. هن جي ڪم جو خلاصو هن ريت آهي: هن طبقي جي هڪ شئي ۾ ٽاسڪ قسم جي عوامي ملڪيت آهي، جنهن جي حالت کي ڪنٽرول ڪري سگهجي ٿو SetResult، SetException وغيره. TaskCompletionSource طبقي جي طريقن سان. جڳهن ۾ جتي انتظار آپريٽر هن ٽاسڪ تي لاڳو ڪيو ويو هو، اهو عمل ڪيو ويندو يا هڪ استثنا سان ناڪام ٿيندو 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 Tips & Tricks

پراڻن APIs کي لپائڻ اهو سڀ ڪجهه نه آهي جيڪو استعمال ڪري سگهجي ٿو TaskCompletionSource. هن ڪلاس کي استعمال ڪرڻ سان مختلف APIs کي ڊزائين ڪرڻ جو هڪ دلچسپ امڪان پيدا ٿئي ٿو ٽاسڪ تي جيڪي موضوعن تي قبضو نٿا ڪن. ۽ وهڪرو، جيئن اسان کي ياد آهي، هڪ قيمتي وسيلو آهي ۽ انهن جو تعداد محدود آهي (خاص طور تي رام جي مقدار ۾). اها حد آساني سان ترقي ڪندي حاصل ڪري سگهجي ٿي، مثال طور، پيچيده ڪاروباري منطق سان ڀريل ويب ايپليڪيشن. اچو ته انهن امڪانن تي غور ڪريون جن بابت آئون ڳالهائي رهيو آهيان جڏهن لانگ پولنگ وانگر اهڙي چال کي لاڳو ڪرڻ.

مختصر ۾، چال جو جوهر هي آهي: توهان کي API کان معلومات حاصل ڪرڻ جي ضرورت آهي ڪجهه واقعن بابت ان جي پاسي تي واقع ٿيندي، جڏهن ته API، ڪجهه سببن لاء، واقعي جي رپورٽ نه ڪري سگهي، پر صرف رياست کي واپس ڪري سگهي ٿو. انهن جو هڪ مثال اهي سڀئي APIs آهن جيڪي HTTP جي چوٽي تي WebSocket جي وقت کان اڳ ٺاهيا ويا آهن يا جڏهن هن ٽيڪنالاجي کي استعمال ڪرڻ لاء ڪجهه سببن لاء ناممڪن هو. ڪلائنٽ HTTP سرور کان پڇي سگھي ٿو. HTTP سرور پاڻ کي ڪلائنٽ سان رابطي کي شروع نٿو ڪري سگهي. ھڪڙو آسان حل آھي سرور کي ٽائمر استعمال ڪندي پولنگ ڪرڻ، پر اھو سرور تي اضافي لوڊ ۽ اوسط 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 استعمال ڪرڻ بابت سوچي سگهو ٿا.

جڏهن اسان کي پيغام جي درخواست ملي ٿي، اسان ڊڪشنري ۾ هڪ TaskCompletionSource ٺاهي ۽ رکون ٿا، ۽ پوءِ انتظار ڪريون ٿا ته پهرين ڇا ٿئي: مخصوص وقت جو وقفو ختم ٿئي ٿو يا پيغام ملي ٿو.

ValueTask: ڇو ۽ ڪيئن

async/await آپريٽر، جهڙوڪ yield ريٽرن آپريٽر، طريقي مان هڪ رياستي مشين ٺاهي، ۽ هي هڪ نئين شئي جي تخليق آهي، جيڪا لڳ ڀڳ هميشه اهم ناهي، پر نادر ڪيسن ۾ اهو مسئلو پيدا ڪري سگهي ٿو. اهو معاملو ٿي سگهي ٿو هڪ طريقو جنهن کي سڏيو ويندو آهي واقعي اڪثر، اسان ڳالهائي رهيا آهيون ڏهن ۽ سئو هزارين ڪالن جي في سيڪنڊ بابت. جيڪڏهن اهڙي طريقي سان لکيو ويو آهي ته اڪثر ڪيسن ۾ اهو نتيجو واپس آڻيندو آهي سڀني انتظار جي طريقن کي نظرانداز ڪندي، پوء .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));
}

اچو ته ڪوڊ جي هن ٽڪرا تي هڪ ويجهي نظر رکون: جيڪڏهن ڪيش ۾ هڪ قدر آهي، اسان هڪ ساخت ٺاهي سگهون ٿا، ٻي صورت ۾ حقيقي ڪم هڪ معني ۾ لپي ويندو. ڪالنگ ڪوڊ کي پرواه ناهي ته هي ڪوڊ ڪهڙي رستي تي عمل ڪيو ويو آهي: ValueTask، C# نحوي نقطي نظر کان، هن معاملي ۾ هڪ عام ٽاسڪ وانگر ساڳيو ئي عمل ڪندو.

TaskSchedulers: انتظام ڪرڻ ٽاسڪ لانچ حڪمت عمليون

ايندڙ API جنهن تي آئون غور ڪرڻ چاهيندس ڪلاس آهي ٽاسڪ شيڊيولر ۽ ان جا نڪتل. مون اڳ ۾ ئي مٿي ذڪر ڪيو آهي ته TPL وٽ ٽاسڪ کي ورهائڻ لاءِ حڪمت عمليون منظم ڪرڻ جي صلاحيت آهي. اهڙيون حڪمت عمليون TaskScheduler طبقي جي اولاد ۾ بيان ڪيون ويون آهن. تقريبن ڪا به حڪمت عملي جيڪا توهان کي گهربل هجي لائبريري ۾ ملي سگهي ٿي. Parallel Extensions Extras, Microsoft پاران تيار ڪيل، پر .NET جو حصو نه، پر هڪ Nuget پيڪيج جي طور تي فراهم ڪيو ويو. اچو ته مختصر طور انهن مان ڪجهه کي ڏسو:

  • CurrentThreadTaskScheduler - موجوده سلسلي تي ڪمن کي انجام ڏئي ٿو
  • Limited Concurrency LevelTask ​​شيڊيولر - محدود ڪري ٿو ٽاسڪ جو تعداد هڪ ئي وقت تي عمل ڪيو ويو پيرا ميٽر N طرفان، جيڪو تعمير ڪندڙ ۾ قبول ڪيو ويو آهي
  • آرڊر ٿيل ٽاسڪ شيڊولر - جي وضاحت ڪئي وئي آهي LimitedConcurrencyLevelTaskScheduler(1)، تنهن ڪري ڪمن کي ترتيب سان انجام ڏنو ويندو.
  • WorkStealingTaskScheduler - اوزار ڪم چوري ڪرڻ ڪم جي ورڇ جو طريقو. لازمي طور تي اهو هڪ الڳ ThreadPool آهي. اهو مسئلو حل ڪري ٿو ته .NET ThreadPool ۾ هڪ جامد ڪلاس آهي، هڪ سڀني ايپليڪيشنن لاءِ، جنهن جو مطلب آهي ته پروگرام جي هڪ حصي ۾ ان جي اوورلوڊنگ يا غلط استعمال ٻئي ۾ ضمني اثرات پيدا ڪري سگهي ٿي. ان کان سواء، اهڙي خرابين جي سبب کي سمجهڻ تمام ڏکيو آهي. اهو. پروگرام جي حصن ۾ الڳ WorkStealingTaskSchedulers استعمال ڪرڻ جي ضرورت ٿي سگھي ٿي جتي ThreadPool جو استعمال جارحاڻي ۽ غير متوقع ٿي سگھي ٿو.
  • قطار واري ٽاس شيڊيولر - توهان کي ترجيحي قطار جي ضابطن جي مطابق ڪم ڪرڻ جي اجازت ڏئي ٿي
  • ThreadPerTask شيڊيولر - هر ٽاسڪ لاءِ الڳ ٿريڊ ٺاهي ٿو جيڪو ان تي عمل ڪيو وڃي ٿو. ڪمن لاءِ ڪارائتو ٿي سگھي ٿو جيڪي مڪمل ٿيڻ ۾ غير متوقع طور تي ڊگهو وقت وٺن.

تمام سٺو تفصيلي آهي هڪ مضمون Microsoft بلاگ تي TaskSchedulers بابت.

ٽاسڪ سان لاڳاپيل هر شيءِ جي آسان ڊيبگنگ لاءِ، Visual Studio وٽ ٽاسڪ ونڊو آهي. هن ونڊو ۾ توهان ڪم جي موجوده حالت ڏسي سگهو ٿا ۽ ڪوڊ جي هن وقت تي عمل ڪرڻ واري لائن ڏانهن وڃو.

.NET: ملٽي ٿريڊنگ ۽ اسينڪروني سان ڪم ڪرڻ جا اوزار. حصو 1

PLinq ۽ متوازي ڪلاس

ٽاسڪ ۽ انهن جي باري ۾ جيڪي ڪجهه چيو ويو آهي ان کان علاوه، .NET ۾ ٻه وڌيڪ دلچسپ اوزار آهن: PLinq (Linq2Parallel) ۽ Parallel class. پهريون واعدو ڪيترن ئي موضوعن تي سڀني لنڪ عملن جي متوازي عملدرآمد جو. موضوعن جو تعداد استعمال ڪندي ترتيب ڏئي سگھجي ٿو WithDegreeOfParallelism Extension Method. بدقسمتي سان، اڪثر ڪري PLinq ان جي ڊفالٽ موڊ ۾ توهان جي ڊيٽا جي ذريعن جي اندروني بابت ڪافي معلومات نه هوندي آهي ته هڪ اهم رفتار حاصل ڪرڻ لاء، ٻئي طرف، ڪوشش ڪرڻ جي قيمت تمام گهٽ آهي: توهان کي صرف AsParallel طريقي سان ڪال ڪرڻ جي ضرورت آهي. لنڪ جي طريقن جو سلسلو ۽ ڪارڪردگي ٽيسٽ کي هلائڻ. ان کان علاوه، اهو ممڪن آهي ته توهان جي ڊيٽا جي ماخذ جي نوعيت جي باري ۾ PLinq کي اضافي معلومات موڪلڻ لاء Partitions ميڪانيزم استعمال ڪندي. توهان وڌيڪ پڙهي سگهو ٿا هتي и هتي.

متوازي جامد ڪلاس متوازي ۾ Foreach ڪليڪشن ذريعي ورجائڻ لاءِ طريقا مهيا ڪري ٿو، لوپ لاءِ عمل ڪرڻ، ۽ متوازي دعوت ۾ ڪيترن ئي نمائندن تي عمل ڪرڻ. موجوده سلسلي جي عمل کي روڪيو ويندو جيستائين حساب ڪتاب مڪمل نه ڪيو وڃي. آخري دليل طور ParallelOptions کي پاس ڪندي سلسلي جو تعداد ترتيب ڏئي سگھجي ٿو. توھان پڻ بيان ڪري سگھو ٿا TaskScheduler ۽ CancellationToken اختيارن کي استعمال ڪندي.

پهچڻ

جڏهن مون پنهنجي رپورٽ جي مواد ۽ ان کان پوءِ پنهنجي ڪم دوران گڏ ڪيل معلومات جي بنياد تي هي مضمون لکڻ شروع ڪيو ته مون کي اها اميد نه هئي ته ان ۾ ايترو ڪجهه هوندو. هاڻي، جڏهن ٽيڪسٽ ايڊيٽر جنهن ۾ مان هي مضمون ٽائيپ ڪري رهيو آهيان، مون کي طعنن سان ٻڌائي ٿو ته صفحو 15 هليو ويو آهي، مان عبوري نتيجن جو خلاصو ڪندس. ٻيون چالون، APIs، بصري اوزار ۽ نقصان ايندڙ مضمون ۾ شامل ڪيا ويندا.

نتيجو:

  • جديد پي سيز جا وسيلا استعمال ڪرڻ لاءِ توهان کي موضوعن سان ڪم ڪرڻ لاءِ اوزارن کي ڄاڻڻ جي ضرورت آهي، asynchrony ۽ parallelism.
  • .NET انهن مقصدن لاءِ ڪيترائي مختلف اوزار آهن
  • اهي سڀئي هڪ ئي وقت ۾ ظاهر نه ٿيا، تنهنڪري توهان اڪثر ڪري ورثي وارا ڳولي سگهو ٿا، جڏهن ته، پراڻي APIs کي تبديل ڪرڻ جا طريقا آهن بغير ڪنهن ڪوشش جي.
  • .NET ۾ ٿريڊز سان ڪم ڪرڻ کي ٿريڊ ۽ ٿريڊ پول طبقن جي نمائندگي ڪري ٿو
  • Thread.Abort، Thread.Interrupt، ۽ Win32 API TerminateThread طريقا خطرناڪ آهن ۽ استعمال لاءِ سفارش نه ڪيا ويا آهن. ان جي بدران، اهو استعمال ڪرڻ بهتر آهي CancellationToken ميڪانيزم
  • وهڪري هڪ قيمتي وسيلو آهي ۽ ان جي فراهمي محدود آهي. اهڙين حالتن کان پاسو ڪيو وڃي جتي موضوعن جي انتظار ۾ مصروف هجن. ان لاءِ اهو استعمال ڪرڻ آسان آهي TaskCompletionSource ڪلاس
  • سڀ کان وڌيڪ طاقتور ۽ ترقي يافته .NET اوزار متوازي ۽ asynchrony سان ڪم ڪرڻ لاءِ ڪم آهن.
  • c# async/await آپريٽرز غير بلاڪنگ انتظار جي تصور کي لاڳو ڪن ٿا
  • توھان ٽاسڪ شيڊولر مان نڪتل ڪلاسز استعمال ڪندي ٽاسڪ جي ورڇ کي ٿريڊن ۾ ڪنٽرول ڪري سگھو ٿا
  • ValueTask ڍانچي گرم رستا ۽ ميموري-ٽريفڪ کي بهتر ڪرڻ ۾ ڪارائتو ٿي سگهي ٿو
  • بصري اسٽوڊيو جا ٽاسڪ ۽ ٿريڊس ونڊوز ملٽي ٿريڊ يا اسيئنڪرونس ڪوڊ ڊيبگ ڪرڻ لاءِ تمام گهڻي مفيد معلومات مهيا ڪن ٿيون
  • PLinq هڪ بهترين اوزار آهي، پر ٿي سگهي ٿو ته ان ۾ توهان جي ڊيٽا ماخذ جي باري ۾ ڪافي معلومات نه هجي، پر ان کي تقسيم ڪرڻ واري ميڪانيزم کي استعمال ڪندي طئي ڪري سگهجي ٿو.
  • جاري رکڻ گهرجي…

جو ذريعو: www.habr.com

تبصرو شامل ڪريو