Goroutines

Goroutines
Goroutines

Một trong các điểm mạnh của Go đó là khả năng sử lý đa luồng nó là một trong những vấn đề được các nhà phát triển golang chú trọng hàng đầu. Go đưa ra 2 tính năng hỗ trợ concurrency rất mạnh đó là Goroutine và Channel. Ở bài viết này chúng ta sẽ tập trung vào Goroutine trong Go. Trước tiên cùng đi qua các khái niệm 1 chút.!

1. Concurrency

Xử lý concurrency (đồng thời) nghĩa là có khả năng giải quyết nhiều công việc một lúc, và những công việc đó ko nhất thiết phải xảy ra tại cùng một thời điểm. Hay nói ngắn gọn hơn là việc nhiều task được xử lý cùng một lúc.

2. Goroutines

Cơ chế hoạt động và cách sử dụng

Cơ chế của goroutine khá đơn giản: 1 function tồn tại một cách đa luồng với các goroutine khác trên cùng một không gian bộ nhớ, Go có bộ điều khiển quản lý các goroutine, rồi phân phối chúng vào các bộ xử lý logic và gắn mỗi bộ xử lý logic này với một thread hệ thống được tạo ra trước đó để thực thi các goroutine này. Nói cách khác, mỗi thread hệ thống sẽ xử lý một nhóm goroutine được điều phối thông qua bộ xử lý logic. Với bộ điều khiển quản lý tác vụ đồng thời và cơ chế bộ xử lý logic, những cái khó khăn, phức tạp khi khai báo thread Go đã xử lý hết giúp chúng ta rồi, chúng ta chỉ việc sử dụng thôi.

Để khởi tạo một goroutine ta chỉ cần thêm phía trước một function call hay method call từ khoá go . VD: Hiển thị số tuần tự từ 1 đến 20 và không sử dụng goroutine.

package main

import (
	"fmt"
)

func main() {
	g1()
	g2()
}

func g1() {
	for i := 1 ; i <= 10 ; i++ {
		fmt.Println(i)
	}
}

func g2() {
	for i := 11 ; i <= 20 ; i++ {
		fmt.Println(i)
    }
}
Hiển thị số từ 1 đến 20

ví dụ trên có 2 hàm là
g1() : hiển thị các số từ 1 đến 10
g2() : hiển thị các số từ 11 đến 20.

Do hàm g1() viết trước hàm g2() nên g1() sẽ thực thi trước g2(), khi đó g2() sẽ phải chờ g1() thực thi xong và kết quả sẽ hiển thị các số từ 1 đến 20 một cách tuần tự.

Kết quả sau khi chạy chương trình

VD: hiển thị số từ 1 đến 20 sử dụng goroutines

package main

import (
	"fmt"
	"time"
)

func main() {
	go g1()
	go g2()
	time.Sleep(time.Second)
}

func g1() {
	for i := 1; i <= 10; i++ {
		go fmt.Println(i)
	}
}

func g2() {
	for i := 11; i <= 20; i++ {
		go fmt.Println(i)
	}
}

Ví dụ trên có 2 hàm là g1() và g2() ta thêm từ khóa go đằng trước tên hàm để thể hiện đây là hàm goroutine, khi đó 2 hàm g1() và g2() sẽ được thực thi đồng thời mà không cần phải chờ hàm trước nó thức thi xong, ta thêm từ khóa go vào trước các câu lệnh fmt.Println(i)fmt.Println(j)để cho chương trình biết các lệnh này cũng được thực thi đồng thời.
lệnh time.Sleep(time.Second) là để chương trình main sleep 1 giây chờ 2 hàm g1(), và g2() kết thúc. Và đây là kết quả của chương trình trên.

Chương trình chạy sau khi sử dụng goroutines

Mỗi lần chạy, các kết quả, thứ tự các chữ số cho ra là khác nhau.

Ưu điểm khi sử dụng goroutines

  • Goroutine rẻ hơn khi so sánh với một thread. Chúng chỉ chiếm vài kb trong kích thước stack và stack có thể tăng hoặc co lại tuỳ theo yêu cầu của ứng dụng, trong khi đó với trường hợp của thread kích thước stack sẽ được chỉ định và cố định
  • Thời gian khởi động của Goroutines nhanh hơn so với Thread
  • Giao tiếp giữa các Goroutines sử dụng channel cực an toàn.
  • Goroutines và OS thread không tồn tại 1:1. Mỗi Goroutines có thể chạy đồng thời nhiều threads, chúng có thể ghép vào OS threads.

Kết bài

Trên đây là bài giới thiệu cơ bản nhất về goroutines, tuỳ vào mục đích của chương trình mà các bạn có thể quyết định có sử dụng goroutines hay không.

Bye, see you later !