توجه : این نوشته برداشتی از کتاب Concurrency in C# Cookbook نوشته Stephen Cleary می باشد
قبل از هر چیز، بهتر است واژگانی که در ادامه از آنها استفاده خواهیم کرد را شفاف کنیم. اینها تعریف هایی است که من بصورت معمول از آنها برای ابهام زدایی از اصطلاحات برنامه نویسی استفاده می کنم.
همزمانی: انجام بیش از یک کار در یک زمان
به نظرم مشخص شد که چرا همزمانی، یک تکنیک بدردبخور است. برنامه های End-user از همزمانی برای نوشتن روی پایگاه داده، در حین پاسخ دادن به ورودی های کاربر استفاده می کنند. برنامه های سمت سرور، از همزمانی برای پاسخ دادن به Request دوم در حین تمام کردن Request اول استفاده می کنند. به همین ترتیب هر برنامه مناسب با کاری که می خواهد انجام بدهد، از همزمانی استفاده می کند تا بتواند روی بیشتر از یک کار را در زمانی که کار دیگری انجام می دهد، پردازش کند. تمام برنامه های نوشته شده در دنیا می توانند از مزایای همزمانی بهره ببرند.
زمانی که از همزمانی صحبت می کنیم، بیشتر توسعه دهندگان، بی درنگ، به یاد برنامه نویسی چند نخی (MultiThreading) می افتند. دوست دارم میان این دو تمایزی ایجاد کنم.
برنامه نویسی چند نخی (MultiThreading) : شکلی از همزمانی که در آن از چندین Thread به جز Thread اصلی برای انجام کار استفاده می شود
همانطور که در ادامه خواهیم دید، MultiThreading یکی از راه های ایجاد همزمانی در نرم افزار است ولی به طور قطع تنها راه نیست. در حقیقت استفاده مستقیم از شکل های سطح پائین Threading، در برنامه های مدرن جایی ندارند، شکل های سطح بالاتر، نه تنها قدرتمندترند، بلکه سود بیشتری از شکل های قدیمی دارند. به همین خاطر درباره تکنیک های تاریخ گذشته کمتر صحبت خواهم کرد. هیچ کدام از دستورالعمل های این کتاب، از تایپ های Thread و BackgroundWorkerاستفاده نمی کنند، در عوض از جایگزین های برتری سخن خواهم گفت.
اما، اصلا فکر نکنید که ایده ی MultiThreadingمرده است. MultiThreading در thread pool زنده است. جایی که صف کار، بصورت اتوماتیک و براساس تقاضا، فعالیت ها را تنظیم می کند. thread pool قایلیت ایجاد یک نوع همزمانی دیگر به نام پردازش موازی (Parallel processing) را فراهم می کند.
پردازش موازی (Parallel processing): مقدار زیادی از کارها را با استفاده از تقسیم آنها در چند نخ (Thread) به صورت همزمان انجام دهیم.
پردازش موازی (یا برنامه نویسی موازی) از MultiThreading کمک می گیرد تا از استفاده از توان هسته های پردازنده را حداکثر کند. پردازنده های مدرن، هسته های متعددی دارند و اگر کار های زیادی برای انجام دادن موجود باشد، معنی ندارد که همه ی کار ها را یک هسته انجام دهد و بقیه بیکار باشند! پردازش موازی کار ها را میان چند Thread تقسیم می کند که می توانند مستقل روی چند هسته مختلف اجرا شوند.
پردازش موازی، یکی از انواع روش های MultiThreading است و MultiThreading، یکی از روش های ایجاد همزمانی. نوع دیگری نیز وجود دارد که با وجود اهمیتش در برنامه های مدرن، برای برخی از توسعه دهندگان آشنا نیست. برنامه نویسی ناهمگام (Asynchronous programming).
برنامه نویسی ناهمگام : یکی از انواع همزمانی که در آن از future ها و یا callback ها برای جلوگیری کردن از ایجاد thread های غیر لازم استفاده می شود.
تایپ های future (یا promise) مشخص کننده ی فعالیت هایی هستند که در آینده تکمیل خواهند شد. در برنامه های مدرن .net از Task and Task<TResult> استفاده می شود. برنامه های قدیمی تر از callback و Event ها به جای از future استفاده می کردند.
برنامه نویسی ناهمگام، حول ایده ی Asynchronous operation (عملیات های ناهمگام) چیده شده است، به این مفهوم که برخی عملیات ها که هم اکنون شروع شده اند، در آینده به اتمام خواهند رسید. بنابراین، تا زمانی که عملیات در حال انجام است، کار Threadاصلی برنامه، با وقفه رو به رو نگردد(منوط به اتمام عملیات نشود). بنابراین، Thread اصلی برنامه ظرفیت دارد تا کار دیگری را انجام دهد. زمانی که عملیات به اتمام رسید، به future خود اطلاع می دهد ویا eventیا callback خود را فعال میکند تا برنامه بداند کار تمام شده است.
برنامه نویسی ناهمگام، یک حالت قدرتمند از همزمانی است اما تا قبل از این نیاز به کدهای بسیار پیچیده ای داشت. با استفاده از async و await به راحتی حالت synchronous (همگام) می توان برنامه نوشت.
فرم دیگری از همزمانی، Reactive programming (برنامه نویسی واکنشی) است. Asynchronous programming یک عملیاتی را شروع می کند که در آینده تمام خواهد شد و همان زمان به سراغ آن خواهد رفت. Reactive programming بسیار شبیه به Asynchronous programming است باید تفاوت که Asynchronous programming از Asynchronous operation ها استفاده می کند ولی Reactive programming از Asynchronous events (رویداد های ناهمگام) استفاده می کند. Asynchronous events ممکن است در زمان مشخصی شروع نشوند و چندین بار فرخوانی شوند. مانند ورود اطلاعات توسط کاربر.
برنامه نویسی واکنشی : یک فرم مشخص کردن محل و نحوه واکنش برنامه به Event ها
اگر یک برنامه را یک ماشین حالت بزرگ در نظر بگیریم، رفتار برنامه می تواند واکنش هایی به یک سری از رویداد ها تلقی شود که در هر Event یک حالت بروز می شود.
این ققط یک مفهوم تئوری یا انتزاع نیست. Framework های مدرن از این رویکرد بصورت کاملا مفید در برنامه های واقعی استفاده می کنند. Reactive programming الزاما همزمان نیست، ولی به چیزی که در ادامه می خواهیم توضیح بدهیم بسیار مربوط است.
بهترین راه حل، استفاده از مخلوطی از این موارد برحسب استفاده است.