
آموزش کلاس های کالکشنی همروند Concurrent Collection ها در سی شارپ
آموزش کلاس های کالکشنی همروند Concurrent Collection ها در سی شارپ یکی دیگر از آموزش های گروه آموزشی پرووید می باشد که در این قسمت آن را به شما معرفی می کنیم. این بسته ی آموزشی نیز یکی از دوره های آموزشی دیگر که در حوزه ی فارسی سازی آموزش های انگلیسی تنظیم شده است می باشد. عنوان این بسته ی آموزشی آموزش کالکشن های همروند در سی شارپ است که با نام اصلی C# Concurrent Collections شرکت Pluralsight منتشر شده است.
Collection ها چه هستند؟
به منظور استفاده و مدیریت از گروهای از اشیا در برنامه های دات نت می توان آرایه ای از اشیا و یا Collection ی از اشیا را ساخت. کاربرد آرایه ها بیشتر در کار کردن با تعداد مشخصی از اشیا می باشد که همگی از یک نوع یکسان هستند. به عبارت دیگر آرایه ها در دات نت Strongly Typed هستند.
از طرف دیگر، Collection ها در کار کردن با مجموعه هایی که تعداد اعضای آنها به صورت پویا کم و یا زیاد می شود استفاده می گردند. علاوه بر این، در بعضی از Collection ها، می توان به هر عنصری کلیدی اختصاص داد که با استفاده از آن کلید، عنصر مورد نظر را سریعاً بازیابی کرد. باید بگوییم که یک Collection در اصل یک کلاس می باشد. بنابراین، برای استفاده از آنها باید یک شی از کلاس مورد نظر را ساخت.

اگر مجموعه ای که قصد کار کردن با آن را دارید شامل عناصری می شود که همگی از یک جنس هستند می توانید از کلاس هایی که در System.Collections.Generic می باشند استفاده کنید. Collection هایی که جنریک هستند به ما امکان اضافه کردن اشیا غیرهمجنس را به مجموعه نمی دهند. علاوه بر این، در زمان بازیابی عنصری از این مجموعه ها نیازی به تشخیص نوع آن عنصر نیست.
Concurrent Collection ها چه هستند؟
در دات نت فریم ورک 4 یک namespace با نام System.Collections.Concurrent معرفی شد که حاوی کلاس های کالکشنی می باشد که نه تنها Thread-safe هستند بلکه مقیاس پذیری بالایی نیز دارند. به عبارت دیگر در برنامه نویسی همروند چندین Thread می توانند بدون نگرانی از بوجود آمدن مشکلات مربوط به برنامه های همروند از قبیل شرایط Race اقدام به درج عناصر در این کلاس ها و حذف عناصر از درون آنها کنند. این موضوع نیازی به Thread Synchronization اضافی در کد شما ندارد.

ضمناً توصیه می کنیم که از آموزش مباحث پیشرفته کالکشن ها Collection ها در سی شارپ و آموزش کلاس های کالکشنی در سی شارپ نیز دیدن کنید.
ConcurrentDictionary و متدهای Atomic در برنامههای چندریسمانی
زمانی که چند Thread بهطور همزمان یک مجموعه داده را تغییر میدهند، عملیات خواندن و نوشتن باید با توجه به رقابت میان Threadها طراحی شوند. این آموزش کار با `ConcurrentDictionary` را بررسی میکند و به متدهای `Thread-safe` و عملیات `Atomic` میپردازد. چنین عملیاتی برای سناریوهایی اهمیت دارند که چند بخش از برنامه بهصورت همزمان مقدارهای یک Dictionary را بهروزرسانی میکنند. با این حال، Thread-safe بودن یک متد به این معنا نیست که هر توالی چندمرحلهای از عملیات نیز خودکار ایمن خواهد بود؛ بنابراین شناخت رفتار دقیق متدها برای جلوگیری از ناسازگاری دادهها ضروری است.
یکی از مثالهای آموزش به مشکل `TryUpdate` میپردازد و با استفاده از سناریوی `BuyAndSell` نشان میدهد چرا باید رفتار بهروزرسانی مقدارها را با دقت بررسی کرد. همچنین جمعزدن مقادیر `ConcurrentDictionary` با استفاده از `LINQ` مطرح میشود تا با پردازش دادههای موجود در یک کالکشن همروند آشنا شوید. این مثالها به توسعهدهندگانی کمک میکنند که در برنامههای چندریسمانی با شمارندهها، وضعیتهای مشترک یا دادههای قابلتغییر سروکار دارند. درک محدودیتهای عملیات اتمیک و تفاوت میان ایمنی یک متد و ایمنی کل منطق تجاری، بخش مهمی از طراحی صحیح این نوع کدهاست.
انتخاب Queue، Stack و BlockingCollection برای Producer-Consumer
در الگوی `Producer-Consumer`، یک بخش از برنامه داده تولید میکند و بخش دیگری آن را پردازش میکند؛ در نتیجه، انتخاب کالکشن مناسب میتواند بر نحوه تبادل داده میان این بخشها اثر بگذارد. این آموزش `ConcurrentQueue`، `ConcurrentStack` و کالکشنهای مرتبط با این الگو را بررسی میکند و سپس به `IProducerConsumerCollection<T>` و `BlockingCollection<T>` میرسد. برای مثال، میتوان از Queue برای پردازش آیتمها بر اساس ترتیب ورود استفاده کرد، درحالیکه Stack رفتار متفاوتی برای دریافت آیتمها دارد. شناخت تفاوت این ساختارها کمک میکند انتخاب کالکشن با منطق کاری برنامه هماهنگ باشد.
بخش عملی آموزش شامل ثبت اشیای `Trade` در Queue و بررسی چالش `Polling` است. وقتی مصرفکننده مرتب بررسی میکند که آیا داده جدیدی رسیده است یا نه، نحوه انتظار برای آیتمها و میزان کار اضافی ایجادشده اهمیت پیدا میکند. `BlockingCollection` میتواند در سناریوهای Producer-Consumer برای هماهنگسازی دسترسی به دادهها و انتظار مصرفکننده هنگام خالی بودن مجموعه مورد استفاده قرار گیرد. آموزش همچنین به Best Practiceها و مسئله Performance میپردازد تا بتوانید علاوه بر صحت دسترسی همزمان، هزینه اجرای راهکار را نیز ارزیابی کنید. این مباحث برای برنامههایی کاربرد دارند که پردازش موازی کارها یا صفهای داخلی دارند.
سرفصل مطالب آموزش ویدئویی Concurrent Collection ها (کالکشن های همروند) در سی شارپ
فصل اول: معرفی کالکشن های همروند
- مقدمه ی دوره ی آموزشی
- مقدمه
- معرفی برنامه ی نمونه: The Geek Clothing Company
- چند نخی (Multithreaded) کردن Queue
- رفع مشکل برنامه با کلاس جنریک ConcurrentQueue
- دلیل شکست مدت Enqueue از کلاس جنریک Queue
- متدهای Atomic
- چرا استفاده از قفل (lock) ها همیشه مناسب نیست
- کالکشن های همروند همیشه از قفل ها استفاده نمی کنند
- کالکشن های همروند و شرایط Race
- انوع کالکشن های همروند
- اینترفیس جنریک IProducerConsumerCollection و کلاس جنریک BlockingCollection
- کلاس جنریک Partitioner و کلاس جنریک OrderablePartitioner
- جمع بندی
فصل دوم: معرفی کلاس ConcurrentDictionary
- مقدمه
- عملیات اصلی Dictionary ها
- تبدیل کردن به ConcurrentDictionary
- چرا متد Add از کلاس ConcurrentDictionary مخفی است
- تعدادی از متدهای Thread-safe
- الگوی متدهای TryXXX و متد TryGetValue
- متد TryAdd
- متد TryRemove
- متد TryUpdate
- مشکل TryUpdate
- متد AddOrUpdate
- چالش بوجود آمدن شرایط Race
- هر عملیات را در یک فراخوان متد تک انجام دهید
- متد GetOrAdd
- جمع بندی
فصل سوم: تمرین عملی با کلاس ConcurrentDictionary
- مقدمه
- معرفی مثال BuyAndSell
- الگوریتم Buy-Sell
- استفاده از AddOrUpdate برای به روز رسانی Concurrent Dictionary
- استفاده از Interlock.Add برای به روز رسانی متغیر Total
- متدهای Thread-safe بدون استفاده از قفل
- چرا نمی توانیم از TryUpdate استفاده کنیم
- به روز رسانی شرطی Concurrent Dictionary
- اعمال شرط توسط Lambda در متد AddOrUpdate
- چالش مربوط به عوارض جانی متدها (Side-effect ها)
- متد AddOrUpdate و اجتناب از منطق های شرطی
- جمع زدن مقادیر Concurrent Dictionary با استفاده از LINQ
- استفاده از متد GetOrAdd برای نمایش مقادیر
- تست کردن برنامه ی مثال در شرایط دشوار
- جمع بندی
فصل چهارم: کالکشن های Producer-Consumer از قبیل Queue ،Stack و Bag
- مقدمه
- مروری بر Queue
- معرفی کلاس جنریک ConcurrentQueue
- معرفی کلاس جنریک ConcurrentStack
- معرفی کلاس جنریک ConcurrentBag
- سناریوهای Producer-Consumer (تولید کننده - مصرف کننده) کدامند؟
- اینترفیس جنریک IProducerConsumerCollection
- جمع بندی
فصل پنجم: تمرین عملی با کالکشن های Producer-Consumer و BlockingCollection
- مقدمه
- معرفی برنامه ی مثال SalesBonuses
- Log کردن اشیا Trade به یک Queue
- درج عناصر در Concurrent Queue
- حلقه ی مصرف کننده: نظارت بر Concurrent Queue
- جریان اصلی برنامه
- محاسبه ی Bonus ها
- چالش Polling
- معرفی کلاس جنریک BlockingCollection
- استفاده از متد Take از کلاس جنریک BlockingCollection برای جلوگیری از Polling
- ارتباط کلاس جنریک BlockingCollection و اینترفیس IProducerConsumerCollection
- قابلیت های دیگر کلاس جنریک BlockingCollection
- جمع بندی
فصل ششم: بعضی از Best Practice های کار کردن با Concurrent Collection ها
- مقدمه
- کالکشن های همروند و مسئله ی Performance
- بنچ مارک کردن کلاس ConcurrentDictionary با چندین Thread
- دسترسی پراکنده به Shared State
- کلاس ConcurrentDictionary از قفل های دانه ریز استفاده می کند
- متد IsEmpty و پروپرتی Count در ConcurrentDictionary عملکرد بدی دارد
- از اتکا به State یک ConcurrentDictionary خودداری کنید
- Enumerate کردن و تغییر در یک کالکشن معمولی
- Enumerate کردن و تغییر در یک کالکشن همروند
- چه هنگان استفاده از کالکشن های همروند توصیه می شود؟
- جمع بندی
- جمع بندی بسته ی آموزشی







