Go با مثال: بستن کانال‌ها

بستن یک کانال نشان می‌دهد که دیگر مقداری روی آن فرستاده نخواهد شد. این کار برای اعلام پایان کار به گیرنده‌های کانال مفید است.

package main
import "fmt"

در این مثال از کانال jobs استفاده می‌کنیم تا کارهایی را که باید انجام شوند از گوروتین main() به یک گوروتین worker بفرستیم. وقتی کار دیگری برای worker نداشته باشیم، کانال jobs را با close می‌بندیم.

func main() {
    jobs := make(chan int, 5)
    done := make(chan bool)

این گوروتین worker است. پشت سر هم با j, more := <-jobs از jobs دریافت می‌کند. در این شکل خاص دومقداری از دریافت، اگر jobs بسته شده باشد و همهٔ مقادیر کانال قبلاً دریافت شده باشند، مقدار more برابر false خواهد بود. از این برای خبر دادن روی done استفاده می‌کنیم، وقتی همهٔ کارها انجام شده باشند.

    go func() {
        for {
            j, more := <-jobs
            if more {
                fmt.Println("received job", j)
            } else {
                fmt.Println("received all jobs")
                done <- true
                return
            }
        }
    }()

این بخش ۳ کار را از طریق کانال jobs به worker می‌فرستد و سپس کانال را می‌بندد.

    for j := 1; j <= 3; j++ {
        jobs <- j
        fmt.Println("sent job", j)
    }
    close(jobs)
    fmt.Println("sent all jobs")

با روش همگام‌سازی که قبلاً دیدیم، منتظر worker می‌مانیم.

    <-done

خواندن از یک کانال بسته بلافاصله موفق می‌شود و مقدار صفرِ نوع زیربنایی را برمی‌گرداند. مقدار بازگشتی دوم (اختیاری) اگر مقدار دریافت‌شده حاصل یک ارسال موفق به کانال باشد true است، و اگر مقدار صفری باشد که به دلیل بسته و خالی بودن کانال تولید شده، false است.

    _, ok := <-jobs
    fmt.Println("received more jobs:", ok)
}
$ go run closing-channels.go 
sent job 1
received job 1
sent job 2
received job 2
sent job 3
received job 3
sent all jobs
received all jobs
received more jobs: false

ایدهٔ کانال‌های بسته ما را به‌طور طبیعی به مثال بعدی می‌رساند: range روی کانال‌ها.

مثال بعدی: .