مروری بر کتاب Concurrency in go

در این مقاله قصد دارم به معرفی کتاب concurrency in go، نوشته‌ی Katherine Cox-Buday بپردازم. هدف من از معرفی این کتاب، آشنایی خواننده با بیان موارد کلی و جزئی‌تری است که در کتاب به آنها پرداخته شده تا توسعه دهنده در صورت نیاز بتواند فصل مربوطه را به صورت عمیق مطالعه کند.

این کتاب، که در شش فصل نوشته شده، به تکنیک‌های همروندی یا concurrency و حل مسائل پیچیده‌تر همروندی در golang می‌پردازد. نویسنده تلاش کرده تا در هر فصل با استفاده از کدهای مناسب، تکنیک‌ها و چالش‌های پیش رو را توضیح دهد. کدهای توضیح داده شده نیز در گیت‌هاب موجود است.

فصل اول: معرفی concurrency

این فصل با توضیحاتی در مورد سابقه‌ی همروندی در دنیای کامپیوتر شروع شده و به تعریفی از concurrency می‌پردازد. concurrency، مباحث تئوری و عملی بسیاری دارد ولی در این کتاب همروندی را به صورت کاربردی و در قالب مثال‌هایی به زبان golang بیان می‌کند.

نوشتن یک برنامه حاوی کدهای همروند بخصوص در زبان برنامه‌نویسی golang، چندان کار مشکلی نیست ولی همروندی چالش‌ها و مشکلاتی را در پی دارد که اجرای صحیح برنامه را با اختلال مواجه می‌کند. در این فصل چالش‌های مربوط به همروندی توضیح داده می‌شود. مواردی مانند:

  • Race conditions
  • Deadlock
  • livelock
  • starvation

فصل دوم: Communicating Sequential Processes

این فصل با تفاوت بین concurrency و parallel شروع می‌شود. توسعه‌دهندگان معمولا این دو کلمه را بجای یکدیگر استفاده می‌کنند ولی در واقع concurrency، ویژگی قطعه کد و parallelism ویژگی برنامه‌های در حال اجرا است. در ادامه نویسنده به تفاوت بین OS thread و goroutine در golang پرداخته و در مورد Communicating Sequential Processes یا CSP که goroutineها از آن الهام گرفته‌ شده‌اند توضیح می‌دهد.

به منظور حل چالش حافظه‌ی اشتراکی بین threadها، از goroutine و channel استفاده می‌شود ولی همچنان با استفاده از پکیج sync و ویژگی‌های آن می‌توان از حافظه‌ی اشتراکی استفاده کرد. نویسنده برای تصمیم‌گیری بهتر در مورد استفاده از حافظه‌ی اشتراکی و یا channelها، سوالاتی را مطرح کرده تا توسعه‌دهنده بتواند با استفاده از آنها راه‌حل خود را برای همروندی انتخاب کند.

فصل سوم: Go’s Concurrency Building Blocks

در این فصل نویسنده به مدل‌های مربوط به همروندی در گولنگ می‌پردازد. ابتدا goroutine را توضیح داده و نحوه‌ی ایجاد آن در کد را بیان می‌کند. در کد می‌توان یک تابع مستقل و یا یک تکه از کد را در قالب anonymous function، به صورت goroutine اجرا کرد.

مدل دیگر برای اجرای همروند و نیز کنترل نقطه الحاق (joint point)، پکیج sync است که از waitgroup و متد done برای کنترل بیشتر goroutineها استفاده می‌کند. در اینجا mutex و RWmutex برای استفاده از حافظه‌ی اشتراکی نیز توضیح داده شده‌است. Poolها نیز در ادامه شرح داده شده که از این فیچر برای کنترل تعداد goroutineها، بخصوص مواردی که هزینه‌ی سنگینی دارند مانند اتصال دیتابیس، استفاده می‌شود. این نوع داده نیز در پکیج sync پیاده‌سازی شده‌است.

سپس به شرح channel پرداخته که از موارد مشتق شده از CSP است. Channelها برای ارتباط goroutine ها به کار گرفته می‌شوند. ساخت یک channel، نوشتن و خواندن داده‌های channel و چالش‌های پیش‌آمده و موارد استفاده از دستور select از جمله مباحث مطرح شده در این فصل هستند.

فصل چهارم: Concurrency Patterns in Go

این فصل از فصول مهم اصلی کتاب است که به بررسی و توضیح الگوهای همروندی در golang می‌پردازد. نویسنده ابتدا با توضیح در مورد بحث confinement شروع می‌کند.

Confinement is the simple yet powerful idea of ensuring information is only ever available from one concurrent process

و در ادامه آن را به صورت کاربردی با استفاده از کدهای همروند در golang توضیح‌ می‌دهد. سپس الگوهایی از همروندی در golang را شرح می‌دهد. الگوهایی مانند:

  • For-select loop
  • Or-channel
  • Pipelines, fan-in, fan-out
  • Or-done channel
  • Tee channel
  • Bridge channel

فصل پنجم: Concurrency at Scale

در این فصل به استفاده از concurrency در برنامه‌هایی در مقیاس بزرگ می‌پردازد و چالش‌های پیش‌رو در اینگونه برنامه‌ها را شرح داده و راه‌حل ارائه می‌کند.

ابتدا مبحث Error Propagation در بین goroutineها مدنظر است. در این قسمت توضیح می‌دهد که چگونه ارورها از لایه‌های پایینی به سمت لایه‌های بالاتر ارسال شوند تا بتوانند اطلاعات لازم را به توسعه‌دهنده ارائه دهند.

مبحث دوم در این فصل، چالش timeout و cancalation است که چگونه و در چه مواردی نیاز است که در یک سیستم همروند time out اتفاق افتد و در صورت بروز چنین اتفاقی چگونه می‌توان پراسس همروند را متوقف کرد.

مبحث سوم که در اینجا مطرح شده، مربوط به heartbeat برای فرآیندهای همروند است. Heartbeat ها، روشی برای اعلام حیات به لایه‌های بالاتر هستند. در این قسمت نیز نویسنده، با ترکیب channelها و for-select loop راه‌حلی را ارائه می‌دهد.

مبحث چهارم، در مورد Replicated Requsts در سیستم‌هایی است که دریافت پاسخ در کوتاهترین زمان ممکن از اولویت‌های آنها محسوب می‌شود. که این کار با استفاده از فرآیندهای همروند انجام شده و نیاز به کنترل فرایندها پس از رسیدن به پاسخ است.

در مبحث پنجم به Rate Limiting پرداخته که از لحاظ امنیتی نیز حائز اهمیت است. برای شرح این مبحث، ابتدا یک rate limiter ساده را پیاده سازی کرده و سپس به پکیج ratelimiter در گولنگ پرداخته است.

و در آخرین مبحث از این فصل، Healing Unhealthy goroutine مطرح شده است که به درگیر شدن goroutineها در موقعیت‌های بد اشاره می‌کند.

فصل ششم: Goroutines and the Go Runtime

در آخرین فصل، نویسنده به مدیریت goroutine ها و نحوه‌ی پخش شدن آنها بر روی OS thereadها پرداخته است. او استراتژی work stealing را معرفی کرده و برای توضیح این الگوریتم مثال‌هایی را بیان کرده است.

و در آخر با وجود اینکه استفاده از goroutine ها در گولنگ بسیار ساده به نظر می‌رسد، ولی نویسنده در این کتاب ۲۲۰ صفحه‌ای مباحث پایه و پیشرفته‌ای را در این حوزه بیان کرده و هر کدام را به صورت عمیق و کاملا فنی توضیح داده است.