1. Concurrency là gì?

Concurrency là khả năng tổ chức nhiều công việc để chúng có thể tiến triển xen kẽ hoặc đồng thời trong cùng một khoảng thời gian. Thay vì phải thực hiện tất cả công việc theo một trình tự duy nhất, chương trình có thể chuyển đổi giữa nhiều công việc đang chờ hoặc đang xử lý.

Ví dụ, một backend cần xử lý ba request cùng lúc. Nếu chương trình chỉ xử lý tuần tự, request thứ hai có thể phải chờ request thứ nhất hoàn thành, ngay cả khi request thứ nhất đang chờ database trả kết quả. Với concurrency, server có thể tiếp tục xử lý những request khác trong thời gian chờ đó.

Go hỗ trợ concurrency ngay trong ngôn ngữ thông qua goroutine, channel và các công cụ đồng bộ. Những cơ chế này giúp tổ chức chương trình có nhiều công việc mà không cần developer tự quản lý từng OS thread.

2. Phân biệt Concurrency và Parallelism

Hai khái niệm này thường đi cùng nhau nhưng không hoàn toàn giống nhau.

Concurrency nói về cách thiết kế và tổ chức nhiều công việc có thể tiến triển độc lập. Parallelism là việc thực sự thực thi nhiều công việc cùng một thời điểm, thường thông qua nhiều CPU core.

Ví dụ, một ứng dụng tải dữ liệu từ nhiều API có thể gửi request đến API A, B và C mà không cần đợi từng request hoàn thành rồi mới gửi request tiếp theo. Đây là một cách tận dụng concurrency, đặc biệt hữu ích khi thời gian xử lý chủ yếu nằm ở việc chờ network.

Go hỗ trợ cả hai. Runtime của Go quản lý và lập lịch goroutine trên các OS thread; khi cấu hình và tài nguyên cho phép, nhiều goroutine có thể thực sự chạy song song trên các CPU core.

3. Goroutine là gì?

Goroutine là một đơn vị thực thi nhẹ do Go runtime quản lý. Nó cho phép một function chạy đồng thời với phần code đã khởi chạy nó.

Trong Go, chỉ cần thêm từ khóa go trước một lời gọi function là có thể khởi chạy function đó trong một goroutine mới.

package main

import (
    "fmt"
    "time"
)

func sayHello() {
    fmt.Println("Hello from goroutine")
}

func main() {
    go sayHello()

    time.Sleep(time.Second)
    fmt.Println("Main finished")
}

Ở đây, go sayHello() khởi chạy sayHello() trong một goroutine riêng. Function main() tiếp tục thực thi mà không cần chờ sayHello() kết thúc ngay tại dòng đó.

Một đặc điểm quan trọng là goroutine không đồng nghĩa với OS thread. Go runtime có thể lập lịch nhiều goroutine trên một số lượng OS thread phù hợp. Điều này giúp tạo và quản lý nhiều tác vụ đồng thời thuận tiện hơn so với việc tự quản lý thread ở mức hệ điều hành.

Goroutine có tự chạy đến khi hoàn thành không?

Goroutine có thể tiếp tục chạy sau khi function khởi chạy nó đã trả về. Tuy nhiên, goroutine không được bảo đảm sẽ hoàn thành trước khi chương trình kết thúc.

Ví dụ:

func main() {
    go func() {
        fmt.Println("Background task")
    }()
}

Khi main() kết thúc, chương trình có thể kết thúc luôn trước khi goroutine kịp in nội dung. Runtime không tự động chờ tất cả goroutine hoàn thành.

4. Tổng kết

Goroutine & Concurrency là phần cốt lõi của Go khi xây dựng các ứng dụng có nhiều công việc tiến triển đồng thời.

Goroutine cho phép chạy function độc lập; sync.WaitGroup giúp chờ các công việc hoàn thành; channel truyền dữ liệu và phối hợp giữa các goroutine; select giúp chờ nhiều hoạt động; còn mutex và các primitive trong package sync bảo vệ dữ liệu dùng chung.

Bên cạnh những cơ chế này, phải hiểu rõ race condition, deadlock và goroutine leak. Context giữ vai trò quan trọng trong việc truyền deadline và tín hiệu cancellation, đặc biệt với các tác vụ thuộc một request backend. Worker Pool là một pattern hữu ích khi cần giới hạn số lượng công việc chạy đồng thời.

Bài viết khác

Series 7 — Web Quality – Engineering :Testing – Unit Testing, Integration Testing, Web Performance – Core Web Vitals, Code Splitting, Lazy Loading

Series 7 — Web Quality – Engineering Bài 3: Testing – Unit Testing, Integration Testing và End-to-End Testing trong ứng dụng web 1. Vì sao ứng dụng web cần Testing? Trong quá trình phát triển Frontend, chúng ta thường kiểm tra ứng dụng bằng cách chạy website trên trình duyệt, nhấn vào các nút, nhập […]

Series 7 — Web Quality – Engineering : Authentication & Authorization

Series 7 — Web Quality – Engineering Bài 1: Authentication & Authorization – Xác thực và phân quyền trong ứng dụng web 1. Mở đầu Khi xây dựng một ứng dụng web có chức năng đăng nhập, chúng ta thường nghĩ rằng chỉ cần tạo biểu mẫu nhập email, mật khẩu và kiểm tra thông […]

Series 6 – Next.js Advanced – Production: Next.js Build & Deployment

Series 6 – Next.js Advanced & Production Bài 5: Next.js Build & Deployment – Từ mã nguồn đến môi trường Production 1. Mở đầu Trong quá trình phát triển một ứng dụng web, việc chạy thành công trên máy tính cá nhân chưa có nghĩa là ứng dụng đã sẵn sàng để đưa đến người […]

Series 6 – Next.js Advanced – Production: Next.js Internationalized Routing Next.js Static Export

Series 6 – Next.js Advanced & Production   Bài 3: Next.js Internationalized Routing – Tổ chức URL cho website đa ngôn ngữ 1. Mở đầu Sau khi xây dựng cơ chế dịch nội dung và định dạng theo locale, ứng dụng cần một cách để người dùng truy cập đúng phiên bản ngôn ngữ. Ví […]

Series 6 – Next.js Advanced & Production: Metadata & SEO, Internationalization (i18n) & Localization (l10n)

Series 6 – Next.js Advanced & Production Bài 1: Metadata & SEO trong Next.js – Tối ưu thông tin và khả năng hiển thị trên công cụ tìm kiếm 1. Mở đầu Khi xây dựng một website, việc hoàn thiện giao diện và chức năng mới chỉ là một phần của quá trình phát triển. […]

Series 5 – Next.js Fundamentals: CSR, SSR, SSG, ISR và cách lựa chọn

Series 5 – Next.js Fundamentals   Bài 7 : CSR, SSR, SSG và ISR – Các chiến lược Rendering trong Next.js 1. Mở đầu Khi xây dựng một website bằng React, chúng ta thường tập trung vào việc tạo component, quản lý state và hiển thị giao diện trên trình duyệt. Tuy nhiên, khi ứng dụng […]

Leave a Reply

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