اشتراک‌ها
آشنایی با TPL Dataflow در سی شارپ

What is TPL Dataflow?

TPL Dataflow (Task Parallel Library Dataflow) is a .NET Framework library designed for building robust and scalable concurrent data processing pipelines. It offers a declarative model in which you define a network of interconnected "blocks" that process and transport data, enabling efficient and flexible parallelism.



آشنایی با TPL Dataflow در سی شارپ
اشتراک‌ها
مقدمه ای بر برنامه نویسی همزمان

What is concurrent programing? Simply described, it’s when you are doing more than one thing at the same time. Not to be confused with parallelism, concurrency is when multiple sequences of operations are run in overlapping periods of time. In the realm of programming, concurrency is a pretty complex subject. Dealing with constructs such as threads and locks and avoiding issues like race conditions and deadlocks can be quite cumbersome, making concurrent programs difficult to write. Through concurrency, programs can be designed as independent processes working together in a specific composition. Such a structure may or may not be made parallel; however, achieving such a structure in your program offers numerous advantages. 

مقدمه ای بر برنامه نویسی همزمان
اشتراک‌ها
Task Parallel Dataflow در دات نت فریم‌ورک 4.5
کتابخانه (Task Parallel Dataflow (TDF به برنامه نویسان در جهت مدیریت سناریوهای پیچیده موازی کمک خواهد کرد.
Task Parallel Dataflow در دات نت فریم‌ورک 4.5
مطالب
روش‌های مختلف انجام چند کار به صورت همزمان در C# .NET - قسمت اول
آیا تا به حال لیستی از دیتا داشته‌اید که بخواهید بر روی آنها کاری را انجام دهید؟ مثلا لیستی از مشتریان که باید برای تک تک آنها Pdf ای را بسازید، یا لیستی از مشتریان که باید برای تک تک آنها بیمه نامه صادر کنید، یا مثلا لیست اطلاعات بلیط‌های قابل فروش را گرفته‌اید و برای تک تک آنها می‌خواهید کمیسیون حساب کنید و ...

در اکثر مواقعی کاری که برای تک تک آیتم‌ها قرار است انجام شود، ساده است و با استفاده از یک حلقه foreach کار تمام میشود. اما در بعضی مواقع کار زمانبر است؛ حال یا به علت وجود کاری CPU bound مثل درست کردن Pdf و محاسبات، یا کار IO Bound است مثل ارسال یک HTTP Request به ازای هر مشتری، یا ذخیره کردن چیزی در دیتابیس که هم CPU bound است و هم IO bound و ترکیبی از مواردی که گفتیم را دارد.

فرض کنیم صد مشتری داریم و برای تک تک آنها میخواهیم کاری انجام دهیم. اگر از یک foreach ساده استفاده کنیم و هر عمل یک ثانیه طول بکشد، کل روال 100 ثانیه طول می‌کشد که جالب نیست.
public async Task Sample()
{
    var customers = await GetCustomersFromSomeWhere();

    foreach (var customer in customers)
    {
        await DoSomethingWithCustomer(customer);
    }
}
با اندکی جستجو در اینترنت به Task.WhenAll می‌رسیم و مشکلی که دارد این است که هر 100 کار را با هم شروع می‌کند که میتواند اثرات مخربی روی کلیت عملکرد سرور بگذارد:
public async Task Sample()
{
    var customers = await GetCustomersFromSomeWhere();
    await Task.WhenAll(customers.Select(c => DoSomethingWithCustomer(c)));
}
اگر چه می‌توانیم خودمان آیتم‌ها را دسته بندی کنیم و مثلا هر 25 تا 25 آنها را با هم پردازش کنیم، ولی این دسته بندی خیلی معقول نیست، چون RX اینجاست!
public async Task Sample()
{
    var customers = await GetCustomersFromSomeWhere();

    await customers.Select(c => Observable.FromAsync(() => DoSomethingWithCustomer(c))).Merge(maxConcurrent: 25);
}
به خاطر وجود maxConcurrent: 25 در دستور فوق، مشتری‌ها بسته به وضعیت کلی سرور، حداکثر 25 تا 25 تا پردازش می‌شوند، ولی ممکن است مثلا 10 تا 10 پردازش شوند. البته انتظار هوشمندی خیلی زیادی از آن نداشته باشید.

استفاده از Rx وقتی که دستورات داخل DoSomethingWithCustomer به صورت IO bound باشند (اتصال به دیتابیس و ارسال Http Request و ...) به خوبی جواب می‌دهد. ولی اگر دستورات داخل DoSomethingWithCustomer به صورت CPU bound باشند، مثل محاسبات یا ساختن Pdf و ... دیگر این روش جواب نمی‌دهد و اینجاست که باید از Task Parallel Library استفاده کنیم ( البته Task Parallel Libraray یا به اختصار TPL هم برای IO Bound و هم برای CPU Bound مناسب است).
برای استفاده از TPL داریم:
public async Task Sample()
{
    var customers = await GetCustomersFromSomeWhere();

    ActionBlock<Customer> action = new ActionBlock<Customer>(c => DoSomethingWithCustomer(c), new ExecutionDataflowBlockOptions
    {
        MaxDegreeOfParallelism = 25
    }); 

    foreach (var customer in customers)
    {
        action.Post(customer);
    }

    action.Complete();

    await action.Completion;
}
همانطور که می‌بینید، بحث 25 تا 25 تا اجرا کردن در اینجا نیز وجود دارد، با این تفاوت که بسیار هوشمندانه‌تر کارها را به صورتی پیش می‌برد که از منابع سرور به بهینه‌ترین شکل ممکن استفاده شود و همین TPL را هم برای اعمال IO bound و هم اعمال CPU bound مناسب می‌کند.

سایر گزینه هایی که داریم شامل Parallel Linq و Parallel.ForEach است که عموما برای کارهای CPU bound مناسبند.
گزینه‌هایی از قدیم نیز وجود دارند، مانند استفاده از Thread و Semaphore و ... که ابدا استفاده مستقیم از آنها توصیه نمیشود.
البته با TPL و RX میشود کارهای خیلی بیشتری نیز انجام داد و این دو فقط برای این سناریو ساخته نشده‌اند و همه جا جایگزین یکدیگر نیستند و هر دو دنیای وسیعی هستند که توصیه می‌کنم به هر دو نگاهی بیاندازید. همچنین TPL تا جایی که می‌دانم جزو مواردی است که در بیرون از دنیای NET. وجود ندارد و یکی از ارزشمندترین ویژگی‌های Unique در NET. است که به این سادگی چنین مسئله‌ای با این کیفیت حل شود.

توجه داشته باشید که اگر فرآیندی که برای تک تک Customer‌ها در مثال فوق قرار است انجام شود، خود یک روال سنگین و زمان بر باشد، بهتر است از روش‌های دیگری مبتنی بر Event processing و ابزارهایی چون Azure Service Bus یا Mass Transit استفاده کنیم که کمک می‌کنند اگر مثلا سه سرور داریم، بار پردازش آن 100 مشتری مثال ما، بین سه سرور هم پخش شود که این مورد پیچیدگی‌های خود را دارد و در اینجا که فرض بر این است که سناریو خیلی پیچیده و میزان بار خیلی زیاد نیست و همچنین نیازی هم به استفاده از این موارد و اضافه کردن پیچیدگی‌های بیشتر به برنامه نیست. در واقع TPL علیرغم کار بسیار ارزشمندی که می‌کند، در نهایت یک Nuget Package است که در یک دستگاه موبایل Android و با Xamarin نیز قابل استفاده است.

البته این همه داستان نیست. برای مثال در صورتی که فرآیندی بخواهد به صورت Concurrent / Parallel انجام شود و در انجام آن از Entity Framework Db Context استفاده شده باشد، کد به مشکل بر میخورد و خطا می‌دهد، چون یک Instance از DbContext مناسب انجام چند کار همزمان نیست. به واقع تمامی Objectهایی که Thread Safe نباشند، در روش‌های فوق به مشکل بر میخوردند. همچنین بحث مدیریت کردن Transaction در صورتی که بخواهید با دیتابیس هم کار کنید نیز خود مسئله‌ای است که باید حل شود.
حل مسائلی که گفته شد و ادغام کردن روش‌های فوق با بحث Dependency Injection و ... موضوع بحث قسمت بعدی این مطلب است.
اشتراک‌ها
برنامه نویسی چند هسته ای در .NET

In the .NET framework 4+, there is enhanced support for parallel programming, including new class library types, Tasks, Parallel For, Parallel Linq, and concurrent collections. Check out some of these features here. 

برنامه نویسی  چند هسته ای در .NET
اشتراک‌ها
FreshMvvm 1.0 منتشر شد
FreshMvvm is a super light Mvvm Framework designed specifically for Xamarin.Forms. It's designed to be Easy, Simple and Flexible.  
FreshMvvm 1.0 منتشر شد