[Lập trình Golang] Concurrency

Một chương trình lớn thường được tạo bởi nhiều chương trình nhỏ hơn. Ví dụ như một máy chủ web xử lý nhiều request được gọi từ các Web Browsers và các máy chủ phản hồi web HTML . Mỗi một request được xử lý như một chương trình nhỏ

Lý tưởng là các chương trình này có thể chạy các chương trình nhỏ hơn đồng thời (trong trường hợp máy chủ web xử lý nhiều yêu cầu). Thực hiện nhiều hơn một routine đồng thời được gọi là Concurrency. Go có hỗ trợ xử lý đồng thời bằng cách sử dụng goroutines và channels.

Goroutines

Goroutine là một hàm có khả năng chạy đồng thời với các hàm khác. Để tạo một chương trình goroutine, chúng ta sử dụng từ khóa go theo sau là một lệnh gọi hàm:

package main

import "fmt"

func f(n int) {
  for i := 0; i < 10; i++ {
    fmt.Println(n, ":", i)
  }
}

func main() {
  go f(0)
  var input string
  fmt.Scanln(&input)
}

Chương trình này bao gồm hai goroutines. Goroutine đầu tiên là ẩn và là hàm chính của chính nó. Goroutine thứ hai được tạo khi chúng ta gọi go f (0). Thông thường khi chúng ta gọi một hàm, chương trình của chúng ta sẽ thực thi tất cả các câu lệnh trong một hàm và sau đó quay trở lại dòng tiếp theo sau lệnh gọi. Với một chương trình goroutine, chúng ta quay trở lại dòng tiếp theo ngay lập tức và không đợi hàm hoàn thành. Đây là lý do tại sao lệnh gọi đến hàm Scanln đã được đưa vào; nếu không có nó, chương trình sẽ thoát ra trước khi có cơ hội in tất cả các số.

Goroutines rất nhẹ và chúng ta có thể dễ dàng tạo ra hàng nghìn cái trong số chúng. Chúng ta có thể sửa đổi chương trình của mình để chạy 10 goroutines bằng cách thực hiện điều này:

func main() {
  for i := 0; i < 10; i++ {
    go f(i)
  }
  var input string
  fmt.Scanln(&input)
}

Bạn có thể nhận thấy rằng khi bạn chạy chương trình này, ví dụ dưới đây dường như chạy các goroutines theo thứ tự hơn là đồng thời. Hãy thêm một số độ trễ vào hàm bằng time.Sleep và rand.Intn:

package main

import (
  "fmt"
  "time"
  "math/rand"
)

func f(n int) {
  for i := 0; i < 10; i++ {
    fmt.Println(n, ":", i)
    amt := time.Duration(rand.Intn(250))
    time.Sleep(time.Millisecond * amt)
  }
}

func main() {
  for i := 0; i < 10; i++ {
    go f(i)
  }
  var input string
  fmt.Scanln(&input)
}

Tuy nhiên, kết quả cho thấy nó các hàm f dường như chạy đồng thời

3 : 0
0 : 0
1 : 0
2 : 0
6 : 0
7 : 0
9 : 0
5 : 0
8 : 0
4 : 0
5 : 1
4 : 1
2 : 1
4 : 2
7 : 1
3 : 1
6 : 1
1 : 1
3 : 2
0 : 1
4 : 3
9 : 1
8 : 1
...

Channels

Channel cung cấp một cách để hai goroutines giao tiếp với nhau và đồng bộ hóa việc thực thi của chúng. Ta xem ví dụ dưới đây:

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)
}

 

Tham khảo: http://www.golang-book.com/books/intro/10

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses cookies to offer you a better browsing experience. By browsing this website, you agree to our use of cookies.