Kiến trúc Node.js - Node.js xử lý bất đồng bộ như thế nào?

Kiến trúc Node.js - Node.js xử lý bất đồng bộ như thế nào?

Tin ngắn hàng ngày dành cho bạn
  • openai/codex là một dự án mã nguồn mở mới nhất của OpenAI, ngay sau khi họ công bố hai mô hình mới nhất là o3 và o4 mini. Nghe nói cả o3 và o4 mini này rất thích hợp làm Agent nên tung ra codex như một dạng Agent nhỏ nhẹ chạy ngay trong Terminal luôn.

    Về tính ứng dụng, vì nó là Agent nên nó có thể đọc/thêm/sửa/xoá nội dung tệp của bạn luôn. Ví dụ.

    codex "explain this codebase to me"

    Hoặc tích hợp vào pipe line của CI/CD.

    - name: Update changelog via Codex run: | npm install -g @openai/codex export OPENAI_API_KEY="${{ secrets.OPENAI_KEY }}" codex -a auto-edit --quiet "update CHANGELOG for next release"

     À quên mất, phải dùng API của OpenAI nha 😆

    » Xem thêm
  • Có thể nhiều người chưa biết, OpenAI đã mở trang học viện riêng để giúp người dùng học tập và khai thác được tối đa sức mạnh các mô hình ngôn ngữ của họ.

    OpenAI Academy

    » Xem thêm
  • Mới sáng ra đã có tin giật gân: OpenAI muốn mua lại Windsurf với giá 3 tỉ đô 😳

    » Xem thêm

Vấn đề

Ở bài viết trước chúng ta đã được biết node.js là single thread, biết thế nào là các tác vụ I/O đồng bộ lẫn không đồng bộ. Vậy thì trong bài viết này tôi sẽ nói về cách node.js xử lý bất đồng bộ như thế nào.

Trước tiên thì tôi xin phép được nhắc lại một số khái niệm để các bạn nắm rõ vấn đề hơn trước khi đến với cách mà node.js xử lý bất đồng bộ!

Bất đồng bộ là gì?

Nếu như các bạn đã được tiếp xúc với một số ngôn ngữ khác trước khi biết đến Javascript như C, PHP hoặc Java thì đó là những ngôn ngữ được viết theo phong cách đồng bộ, tức là nó sẽ chạy lần lượt những đoạn mã mà bạn viết ra. Tôi lấy ví dụ như một đoạn mã đọc file trong PHP như sau:

<?php
$content = readfile("file.txt");
echo $content;
?>

Ngay sau khi hàm readfile đọc được nội dung của file.txt thì nó sẽ in ngay ra màn hình thông qua lệnh echo, bởi vì echo chỉ được gọi sau khi mà hàm readfile có kết quả. Đó chính là lập trình đồng bộ.

Quay lại với Javascript, cùng là một hàm đọc file sẽ trông như sau:

const content = readFile("file.txt");
console.log(content);

Thì kết quả in ra sẽ không phải là nội dung của file.txt bởi vì readFile là một hàm bất đồng bộ. Nó không được xử lý ngay lập tức mà thay vào đó nó đẩy nhiệm vụ này sang cho một bên khác thực hiện (cụ thể là Thread Pool) rồi tiếp tục gọi luôn hàm console.log. Mà các bạn biết đấy, lúc này content đã kịp có kết quả của việc đọc file đâu nên kết quả in ra chắc chắn là không có gì.

Vậy thì các bạn sẽ thắc mắc

Tại sao bất đồng bộ có ích cho node.js

Node.js xử lý bất đồng bộ như thế nào?

Trước tiên chúng ta hãy nhìn lại sơ đồ của cách thành phần có trong node.js:

Thành phần Node.js

Call stack là nơi chịu trách nhiệm cho việc chạy mã Javascript theo một thứ tự nhất định. Vì chỉ có duy nhất một call stack thế nên chỉ có một mã Javascript được chạy tại một thời điểm, điều đó sẽ gây ra một cuộc tắc nghẽn (chặn) nếu như đoạn mã Javascript mất nhiều thời gian để xử lý.

Node.js Standard Library chứa những thành phần tương tác với hệ thống như các tập tin, các request http, phân giải DNS... mà được libuv cung cấp, hay nói cách khác là những thành phần xử lý các I/O không đồng bộ.

Event loop đơn giản là một vòng lặp vô hạn, nó luôn luôn kiểm tra trong call stack có trống không và nếu trống nó sẽ chuyển các hàm callbacks từ Event queue vào call stack lần lượt theo thứ tự FIFO (First In First Out). Các hàm callbacks trong Event queue được Thread pool chuyển vào sau khi một I/O xử lý xong kết quả.

Tóm lại chúng ta sẽ có luồng xử lý một đoạn mã Javascript có chứa mã bất đồng bộ như sau:

Khi chạy một file js, mã Javascript sẽ lần được được đưa vào call stack để xử lý, nếu gặp bất kì một đoạn mã bất đồng bộ nào nó sẽ chuyển đoạn mã đó sang cho Thread pool và tiếp tục xử lý tiếp. Thread pool sau khi nhận được công việc từ call stack nó sẽ tiến hành xử lý ngay lập tức, sau khi có được kết quả nó chuyển kết quả vào hàm callback mà I/O đó đã đăng kí vào Event queue.

Lúc này Event loop vẫn luôn kiểm tra call stack đã xử lý xong hết mã Javascript trong file js chưa. Và nếu hết rồi nó sẽ di chuyển lần lượt các hàm callbacks từ Event queue sang call stack để nó tiếp tục xử lý.

Và nếu trong các hàm callback tiếp tục có những đoạn mã bất đồng bộ thfi công việc sẽ tiếp tục được lặp lại như các bước ở bên trên.

Chúng ta có thể thấy mặc dù node.js chỉ có một call stack để xử lý mã Javascript thế nhưng lại có nhiều Thread pool để xử lý I/O không đồng bộ vốn dĩ tốn nhiều thời gian. Node.js tận dụng sức mạnh của V8 để xử lý mã Javascript cho nên có thể nói tốc độ xử lý mã Javascript hoàn toàn phụ thuộc vào V8 mà theo như họ nói là rất "nhanh".

Mặc định sẽ có 4 Thread pool được tạo ra mỗi khi khởi chạy, con số này có thể thiết lập lên đến 1024 tùy thuộc vào cấu hình máy chủ của bạn cao hay thấp để tinh chỉnh cho phù hợp.

Cao cấp
Hello

5 bài học sâu sắc

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...