Skip to content

Latest commit

 

History

History
170 lines (127 loc) · 6.72 KB

3_channel.md

File metadata and controls

170 lines (127 loc) · 6.72 KB

Суваг

Зэрэгцээ ажиллаж байгаа хоёр go функц хоорондоо мэдээлэл солилцохдоо суваг ашиглана. Дараах програмд суваг ашигласан байна:

package main
import (
  "fmt"
  "time"
)

func pinger(c chan string) {
    for i := 0; ; i++ {
        c <- "ping"
    }
}

func printer(c chan string) {
    for {
        msg := <- c
        fmt.Println(msg)
        time.Sleep(time.Second * 1)
    }
}

func main() {
    var c chan string = make(chan string)

    go pinger(c)
    go printer(c)

    var input string
    fmt.Scanln(&input)
}

Энэ програм “ping” текстийг тасралтгүй хэвлэх болно, зогсоохын тулд Enter товчлуур дарах хэрэгтэй.

Суваг үүсгэхдээ chan түлхүүр үгийн араас уг сувгаар дамжих өгөгдлийн төрлийг зааж бичнэ. Зүүн сум <- үйлдэл нь сувгаар өгөгдөл илгээх, сувгаас өгөгдөл хүлээн авахад ашиглагдана. c <- "ping" заавар нь "ping" текстийг c сувгаар илгээ гэсэн утгатай юм. msg := <- c заавар нь c сувгаас мессеж уншиж msg хувьсагчид хадгал гэсэн утгатай.

Go функцүүдийн хооронд суваг ашигласнаар тэдгээрийн ажиллагааг харилцан дараалалд оруулдаг. Тухайлбал pinger() функц сувгаар мессеж илгээх бөгөөд түүнийг printer() функц хүлээн авах хүртэл уг цэг дээр ажиллагаа нь зогсох болно. Үүнийг мөн өөрөөр түгжээ гэж хэлдэг.

Өмнөх сувгаар дахиад нэг өгөгдөл илгээдэг go функц нэмж юу болохыг харая:

func ponger(c chan string) {
    for i := 0; ; i++ {
        c <- "pong"
    }
}

main функцийг дараах байдлаар өөрчлөнө:

func main() {
    var c chan string = make(chan string)

    go pinger(c)
    go ponger(c)
    go printer(c)

    var input string
    fmt.Scanln(&input)
}

Дээрх функцийг нэмсэнээр програм “ping” болон “pong” текстүүдийг тасралтгүй хэвлэх болно.

Сувгийн чиглэл

Сувагт чиглэл зааж болно, ингэснээр зөвхөн хүлээж авах эсвэл илгээх чиглэлтэй болно. Жишээлбэл pinger() функцийг дараах байдлаар зөвхөн илгээгч болгон тодорхойлж болно:

func pinger(c chan<- string)

Үүний үр дүнд c суваг уруу зөвхөн өгөгдөл илгээж болно, энэ сувгаас өгөгдөл унших гэж оролдвол алдаа болох болно.

Үүнтэй төстэйгээр printer() функцийг зөвхөн хүлээн авагч болгон өөрчилж болно:

func printer(c <-chan string)

Select

Go хэлэнд сувагтай ажиллахад зориулсан select түлхүүр үг байдаг. Энэ функц нь switch заавартай төстэй ажилладаг. Өөрөөр хэлбэл олон сувгаас дохио ирсэн сувгийг сонгож хариу хүлээн авах, боловсруулах зориулалттай заавар юм.

func main() {
    c1 := make(chan string)
    c2 := make(chan string)

    go func() {
        for {
            c1 <- "from 1"
            time.Sleep(time.Second * 2)
        }
    }()

    go func() {
        for {
            c2 <- "from 2"
            time.Sleep(time.Second * 3)
        }
    }()

    go func() {
        for {
            select {
            case msg1 := <- c1:
                fmt.Println(msg1)
            case msg2 := <- c2:
                fmt.Println(msg2)
            }
        }
    }()

    var input string
    fmt.Scanln(&input)
}

Дээрх програм нь 2 секунд тутамд “from 1” текст, 3 секунд тутамд “from 2” текст хэвлэнэ.

select нь өгөгдөл хүлээн авах боломжтой байгаа сувгийг сонгоно (эсвэл илгээх боломжтой). Хэрэв нэгээс олон сувгаас өгөгдөл унших боломжтой болсон байвал санамсаргүйгээр нэгийг нь сонгоно. Хэрэв ямар ч суваг бэлэн биш байвал бэлэн болтол хүлээнэ.

select зааврыг мөн ихэвчлэн хугацаа хэтрэлт (timeout) тооцоолоход ашигладаг:

select {
case msg1 := <- c1:
    fmt.Println("Мессеж 1", msg1)
case msg2 := <- c2:
    fmt.Println("Мессеж 2", msg2)
case <- time.After(time.Second):
    fmt.Println("timeout")
}

time.After нь өгөгдсөн тодорхой хугацааны дараа мессеж илгээх шинэ суваг үүсгэдэг. Цаг болоход энэ сувгаар дохио ирнэ, энэ дохио нь одоогийн цагийн мэдээлэл байна. Дээрх жишээнд цагийн мэдээлэл нь чухал биш учраас түүнийг хувьсагчид хадгалаагүй байна.

Мөн select зааварт default тохиолдол нэмж болно. default нь бүх суваг бэлэн бус буюу дохио ирэхгүй байх тохиолдол юм.

select {
case msg1 := <- c1:
    fmt.Println("Мессеж 1", msg1)
case msg2 := <- c2:
    fmt.Println("Мессеж 2", msg2)
case <- time.After(time.Second):
    fmt.Println("timeout")
default:
    fmt.Println("өгөгдөл бэлэн суваг алга!")
}

Буферт суваг

Суваг үүсгэх үед сувгийн багтаамжийг заасан хоёр дахь параметр заах боломжтой:

c := make(chan int, 1)

Дээрх заавар нь 1 багтаамжтай суваг үүсгэнэ.

Ердийн суваг нь синхрон байдаг, ө.х сувгийн хоёр талд байгаа илгээгч, хүлээн авагч нь нөгөөгөө бэлэн болтол хүлээдэг. Харин буферт суваг нь асинхрон байдаг; ө.х суваг дүүрэхгүй л бол илгээгч, хүлээн авагчид дээр хүлээлт үүсэхгүй гэсэн үг.