بیاموزید که چگونه گوروتین ها و کانال ها همزمانی کارآمد را در برنامه های Go شما فعال می کنند.
همزمانی یکی از جنبههای حیاتی توسعه نرمافزار مدرن است زیرا برنامهها را قادر میسازد تا چندین کار را به طور همزمان انجام دهند. شما می توانید برنامه هایی بنویسید که عملیات های مختلفی را اجرا می کنند که منجر به بهبود عملکرد، پاسخگویی و استفاده از منابع می شود.
همزمانی یکی از ویژگی های مسئول پذیرش سریع Go است. پشتیبانی داخلی Go از برنامه نویسی همزمان ساده در نظر گرفته می شود و در عین حال به جلوگیری از مشکلات رایج مانند شرایط مسابقه و بن بست کمک می کند.
همزمانی در Go
Go پشتیبانی قوی از همزمانی را از طریق مکانیسمهای مختلف فراهم میکند که همگی در کتابخانه استاندارد و زنجیره ابزار آن موجود است. برنامههای Go از طریق برنامهها و کانالها به همزمانی میرسند.
گوروتین ها توابعی سبک وزن هستند که به طور مستقل اجرا می شوند و همزمان با دیگر گوروتین ها در فضای آدرس یکسان اجرا می شوند. گوروتینها به چندین کار اجازه میدهند تا به طور همزمان بدون مدیریت موضوع صریح پیشرفت کنند. گوروتین ها سبک تر از رشته های سیستم عامل هستند و Go می تواند هزاران یا حتی میلیون ها گوروتین را به طور همزمان اجرا کند.
کانال ها مکانیسم ارتباطی برای هماهنگی و به اشتراک گذاری داده ها بین گوروتین ها هستند. کانال یک مجرای تایپ شده است که به گوروتین ها امکان ارسال و دریافت مقادیر را می دهد. کانالها همگامسازی را برای اطمینان از اشتراکگذاری ایمن دادهها بین گوروتینها فراهم میکنند و در عین حال از شرایط مسابقه و سایر مسائل رایج همزمانی جلوگیری میکنند.
با ترکیب گوروتین ها و کانال ها، Go یک مدل همزمانی قدرتمند و ساده ارائه می دهد که توسعه برنامه های همزمان را با حفظ ایمنی و کارایی ساده می کند. این مکانیسم ها شما را قادر می سازد تا به راحتی از پردازنده های چند هسته ای استفاده کنید و برنامه های کاربردی بسیار مقیاس پذیر و پاسخگو بسازید.
نحوه استفاده از گوروتین برای اجرای همزمان کد
زمان اجرا Go گوروتین ها را مدیریت می کند. گوروتین ها پشته خود را دارند و به آنها اجازه می دهد ردپایی سبک وزن با اندازه اولیه پشته چند کیلوبایتی داشته باشند.
گوروتین ها بر روی چندین رشته سیستم عامل توسط زمان اجرا Go چندگانه می شوند. زمانبندی زمان اجرا Go، آنها را با توزیع کارآمد بار کار بر روی رشتههای موجود برنامهریزی میکند و امکان اجرای همزمان چندین گوروتین در رشتههای کمتر سیستمعامل را فراهم میکند.
ایجاد گوروتین ها ساده است. شما از کلمه کلیدی go و به دنبال آن یک تابع فراخوانی برای اعلام گوروتین ها استفاده خواهید کرد.
func main() {
go function1() // Create and execute goroutine for function1
go function2() // Create and execute goroutine for function2
// ...
}
func function1() {
// Code for function1
}
func function2() {
// Code for function2
}
هنگامی که برنامه با کلمه کلیدی go ()function1 و function2() را فراخوانی می کند، زمان اجرا Go توابع را همزمان به صورت گوروتین اجرا می کند.
در اینجا نمونه ای از استفاده از گوروتین است که متن را در کنسول چاپ می کند:
package main
import (
"fmt"
"time"
)
func printText() {
for i := 1; i <= 5; i++ {
fmt.Println("Printing text", i)
time.Sleep(1 * time.Second)
}
}
func main() {
go printText() // Start a goroutine to execute the printText function concurrently
// Perform other tasks in the main goroutine
for i := 1; i <= 5; i++ {
fmt.Println("Performing other tasks", i)
time.Sleep(500 * time.Millisecond)
}
// Wait for the goroutine to finish
time.Sleep(6 * time.Second)
}
تابع printText به طور مکرر متنی را با یک حلقه for در کنسول چاپ می کند که پنج بار پس از یک ثانیه تاخیر بین هر دستور با بسته زمانی اجرا می شود.
تابع اصلی با فراخوانی go printText یک گوروتین را شروع میکند، که تابع printText را به عنوان یک گوروتین همزمان جداگانه راهاندازی میکند که به تابع اجازه میدهد همزمان با بقیه کدهای تابع اصلی اجرا شود.
در نهایت، برای اطمینان از اینکه برنامه قبل از پایان متن printText خارج نمیشود، تابع time.Sleep برنامه اصلی را به مدت شش ثانیه متوقف میکند. در سناریوهای دنیای واقعی، از مکانیسمهای همگامسازی مانند کانالها یا گروههای انتظار برای هماهنگ کردن اجرای گوروتینها استفاده میکنید.
استفاده از کانال ها برای ارتباط و همگام سازی
گوروتینها دارای پشتیبانی داخلی برای ارتباط و همگامسازی از طریق کانالها هستند که نوشتن کد همزمان را آسانتر از رشتههای سنتی میکنند، که اغلب به مکانیسمهای همگامسازی دستی مانند قفلها و سمافورها نیاز دارند.
میتوانید کانالها را بهعنوان خطوط لوله برای جریان داده بین گوروتینها در نظر بگیرید. یک گوروتین می تواند مقداری را به کانال ارسال کند و گوروتین دیگری می تواند آن مقدار را از کانال دریافت کند. این مکانیسم تضمین می کند که تبادل داده ایمن و هماهنگ است.
شما از اپراتور <- برای ارسال و دریافت داده ها از طریق کانال ها استفاده خواهید کرد.
در اینجا یک مثال برای نشان دادن استفاده اساسی از کانال ها برای ارتباط بین دو گوروتین آورده شده است:
func main() {
// Create an unbuffered channel of type string
ch := make(chan string)
// Goroutine 1: Sends a message into the channel
go func() {
ch <- "Hello, Channel!"
}()
// Goroutine 2: Receives the message from the channel
msg := <-ch
fmt.Println(msg) // Output: Hello, Channel!
}
کانال در تابع main یک کانال بافر نشده به نام ch است که با تابع make() ایجاد شده است. اولین گوروتین پیام “سلام، کانال!” با استفاده از عملگر <- وارد کانال می شود و گوروتین دوم با استفاده از همان عملگر پیام را از کانال دریافت می کند. در نهایت تابع main پیام دریافتی را روی کنسول چاپ می کند.
می توانید کانال های تایپ شده را تعریف کنید. در هنگام ایجاد، نوع کانال را مشخص خواهید کرد. در اینجا مثالی وجود دارد که استفاده از انواع مختلف کانال را نشان می دهد:
func main() {
// Unbuffered channel
ch1 := make(chan int)
// Buffered channel with a capacity of 3
ch2 := make(chan string, 3)
// Sending and receiving values from channels
ch1 <- 42 // Send a value into ch1
value1 := <-ch1 // Receive a value from ch1
ch2 <- "Hello" // Send a value into ch2
value2 := <-ch2 // Receive a value from ch2
}
تابع اصلی دو کانال ایجاد می کند: ch1 یک کانال عدد صحیح بدون بافر است، در حالی که ch2 یک کانال رشته ای بافر با ظرفیت 3 است. می توانید با استفاده از عملگر <- مقادیر را به و از این کانال ها ارسال و دریافت کنید (مقادیر باید برابر باشند. نوع مشخص شده).
میتوانید از کانالها بهعنوان مکانیزمهای همگامسازی برای هماهنگی اجرای گوروتین با اعمال نفوذ در ماهیت مسدود کردن عملیات کانال استفاده کنید.
func main() {
ch := make(chan bool)
go func() {
fmt.Println("Goroutine 1")
ch <- true // Signal completion
}()
go func() {
<-ch // Wait for the completion signal from Goroutine 1
fmt.Println("Goroutine 2")
}()
<-ch // Wait for completion signal from Goroutine 2
fmt.Println("Main goroutine")
}
کانال ch بولی است. دو گوروتین به طور همزمان در تابع اصلی اجرا می شوند. Goroutine 1 با ارسال یک مقدار واقعی به کانال ch سیگنال تکمیل آن را می دهد. Goroutine 2 با دریافت مقداری از کانال منتظر سیگنال تکمیل می شود. در نهایت، گروتین اصلی منتظر سیگنال تکمیل از گوروتین دو است.
شما می توانید برنامه های وب را در Go با جین بسازید
میتوانید همزمان با استفاده از ویژگیهای همزمانی Go، برنامههای وب با کارایی بالا را در Go با Gin بسازید.
میتوانید از Gin برای مدیریت کارآمد مسیریابی HTTP و میانافزار استفاده کنید. با استفاده از گوروتین ها و کانال ها برای کارهایی مانند جستارهای پایگاه داده، تماس های API یا سایر عملیات مسدود کردن، از پشتیبانی همزمان داخلی Go بهره ببرید.