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
  • Ui! Blog đang dính một lỗi bảo mật khá nghiêm trọng. Không biết có bạn nào phát hiện ra chưa. Dù chưa ảnh hưởng đến người dùng nhưng thông qua quá trình Eating your own dog food thì mới phát hiện ra á. Để sửa xong thì mình kể chi tiết.

    » Xem thêm
  • Ngủ dậy thấy bảng tin ngập tràn bài viết về việc Microsoft vừa viết lại trình biên dịch Typescript - tsc bằng Go, hiệu suất cho ra nhanh hơn gấp 10 lần so với cái hiện tại. Wow!

    Nhưng khi nhìn thấy tin này thì trong đầu nảy luôn ra câu hỏi "Tại sao không phải là Rust?". Bạn biết đấy, phong trào viết lại mọi thứ bằng Rust đang nóng hơn bao giờ hết, không ngoa khi nói rằng nó đang càn quét bảng xếp hạng của những công cụ kỳ cựu trước đó.

    Điều thú vị hơn nữa là viêc lựa chọn Go - mang lại hiệu suất tốt nhất cho đến thời điểm hiện tại - như họ nói. Thì rất nhiều người tỏ ra thất vọng vì tại sao không phải là C# 😆. Đấy khi bản nổi tiếng quá làm gì cũng bị xét nét từng tí một, nói chưa chắc ai cũng nghe 🥶

    Why Go? #411

    » Xem thêm
  • Mình đọc được bài viết này Migrating Off Oh-My-Zsh and other recent Yak Shavings - đại ý tác giả lâu nay dùng Oh-My-Zsh (OMZ) nhưng mà giờ đây cuộc chơi đã khác, có nhiều công cụ mạnh mẽ hơn ra đời cho nên anh nhận ra ồ, không cần đến OMZ nhiều như vậy.

    Mình cũng đã thử làm theo vì thấy trường hợp này khá giống với tình hình hiện tại. Thật ngạc nhiên khi khám phá thêm được điều mới mẻ. Hy vọng sẽ sớm lên một bài nói về cuộc di cư tiếp theo này với bạn đọc 😁

    » 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

Tôi & khao khát "chơi chữ"

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên 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...