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?

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.

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.
Author

Xin chào, tôi tên là Hoài - một anh Dev kể chuyện bằng cách viết ✍️ và làm sản phẩm 🚀. Với nhiều năm kinh nghiệm lập trình, tôi đã đóng góp một phần công sức cho nhiều sản phẩm mang lại giá trị cho người dùng tại nơi đang làm việc, cũng như cho chính bản thân. Sở thích của tôi là đọc, viết, nghiên cứu... Tôi tạo ra trang Blog này với sứ mệnh mang đến những bài viết chất lượng cho độc giả của 2coffee.dev.Hãy theo dõi tôi qua các kênh LinkedIn, Facebook, Instagram, Telegram.

Bạn thấy bài viết này có ích?
Không

Bình luận (0)