Công việc nền của nodejs

Chúng ta đã biết node. js có Call Stack, sử dụng Event Loop để xử lý I/O không đồng bộ. Vì vậy nút. js sử dụng chúng như thế nào?

I/O không chặn

Từ ví dụ ở các phần trước ta thấy nút. js đang sử dụng gọi lại để xử lý kết quả của các tác vụ I/O không đồng bộ để không chặn luồng chính. Bất kỳ hoạt động nào gây ra độ kỳ hạn sẽ được thực hiện cùng với một hàm gọi lại để thực hiện khi nó hoàn thành tại bất kỳ thời điểm nào. Các hoạt động này được thực thi song song bằng cách sử dụng Thread Pool và các hàm gọi lại bản chất vẫn được thực thi ở trên luồng chính

Sơ đồ này cho thấy các thành phần chính được liên kết với nhau để cung cấp một hệ thống xử lý I/O không đồng bộ

Công việc nền của nodejs

  • Call Stack sẽ thực thi như đã giải thích ở trên, nhưng khi gặp các hàm có tốc độ cao thì nó sẽ không bị chặn. Thay vào đó, nó sẽ đánh dấu sự kiện đó với chức năng gọi lại và sẽ tiếp tục thực hiện tiếp
  • Nút. Thư viện chuẩn js được thực thi sẽ chạy ở chế độ nền (không phải trong Call Stack) bằng cách sử dụng nhóm luồng (Thread Pool) trong thư viện libuv. Ví dụ. fs là một hàm sẽ được thực thi ở chế độ nền và khi hoàn thành, nó sẽ thêm hàm gọi lại vào Hàng đợi sự kiện
  • Event Queue chứa các hàm gọi lại đang được chờ đợi cho đến khi Event Loop đưa chúng trở lại Call Stack và thực thi
  • Vòng lặp sự kiện sẽ chuyển các chức năng gọi lại từ Hàng đợi sự kiện sang Ngăn xếp cuộc gọi để được thực thi bởi luồng chính. Khi Call Stack trống và Event Queue đang có các hàm chờ xử lý, Event Loop sẽ chuyển chúng sang Call Stack và chúng sẽ được thực thi bởi luồng chính

Do đó, bất kỳ hoạt động I/O nào tốn thời gian sẽ không chặn luồng chính được chuyển đến Thư viện chuẩn để được thực thi ở chế độ nền. Do đó luồng chính vẫn tiếp tục được thực thi tiếp, đó được gọi là bản chất không ngăn chặn (không chặn). Khi hoàn tất kích hoạt I/O, chức năng gọi lại của nó sẽ được thực thi bởi luồng chính bằng cách sử dụng Vòng lặp sự kiện và Hàng đợi sự kiện như đã nói ở trên

I/O trong Standard Library

Hiểu đúng những gì nút. js coi là hoạt động I/O và được thực hiện bởi nhóm luồng nội bộ mà không chặn luồng chính. A number of active I/O in node. js không nhất thiết phải là một phần của thông số kỹ thuật trong ECMAScript, do đó không được khai thác bởi công cụ javascript. Ví dụ. setTimeout được khai thác trong cả hai nút. js và trong các trình duyệt, tuy nhiên cách thức phát triển khai báo nó lại khác nhau ở mỗi nền tảng

Các hoạt động I/O dưới đây được coi là thời gian và sẽ được đưa vào thực hiện trong một nhóm luồng được gọi là Thread Pool

Hệ thống tệp

Các hoạt động được xử lý bởi mô-đun fs như đã đọc hoặc ghi vào tệp. Ví dụ fs.write, fs.readStream

Cuộc gọi mạng

Các cuộc gọi yêu cầu mạng như dns.resolve, dns.lookup, http.get,

1
2
3
4
5
6
0,
for (var i = 0; i < 10000; i++) {
   crypto.createHash(); // CPU intensive task
   // or
   sleep(2); // CPU intensive task
}
console.log('After CPU intensive task');
0…

hẹn giờ

Các hoạt động liên quan đến setTimeout, setImmediate hoặc setInterval. Ngay cả hàm setTimeout(cb, 0) with 0ms speed vẫn sẽ được dẫn đến Event Queue và được thực thi theo thứ tự. Do đó, setTimeout không thể đảm bảo thời gian chính xác mà cuộc gọi lại hàm tối thiểu xác định thời gian có thể được thực hiện

Cần lưu ý rằng không phải tất cả các tác vụ trong thời gian đều là tác vụ I/O. Ví dụ. nhiệm vụ chuyên sâu của CPU trong một vòng lặp không phải là nhiệm vụ I/O và nó sẽ chặn luồng chính. Làm nút đó. js được coi là không phù hợp với các tác vụ chuyên sâu về CPU mà là phù hợp hơn với các tác vụ chuyên sâu về I/O

1
2
3
4
5
6
for (var i = 0; i < 10000; i++) {
   crypto.createHash(); // CPU intensive task
   // or
   sleep(2); // CPU intensive task
}
console.log('After CPU intensive task');

Tại đây, nhiệm vụ CPU chuyên sâu sẽ chặn luồng chính và không thực thi lệnh console ngay lập tức như khi các I/O hoạt động không đồng bộ. Đơn giản là nhiệm vụ chuyên sâu CPU sẽ bắt buộc CPU phải được thực thi ngay lập tức, còn đối với nhiệm vụ phải ràng buộc I/O, nó được chuyển tới libuv để được xử lý không đồng bộ

Cần lưu ý rằng nếu Call Stack không trống do các nhiệm vụ chuyên sâu CPU này chặn luồng chính, thì nó sẽ không thể thực hiện bất kỳ điều gì từ Vòng lặp sự kiện của bất kỳ nhiệm vụ I/O nào đang chờ xử lý và sẽ xử lý.

Tổng kết

Bài viết lần này hơi dài và phức tạp, hy vọng sau khi đọc xong mọi người sẽ nắm lấy. - Nút. js sử dụng gọi lại để xử lý kết quả của tác vụ I/O không đồng bộ. - Các tác vụ I/O không đồng thời được thực hiện song song trong Thread Pool được cung cấp bởi libuv. - Không phải tất cả các nhiệm vụ trong thời gian đều là I/O không đồng bộ. - Các nhiệm vụ chuyên sâu CPU sẽ chặn luồng chính do đó sẽ phát triển đến trạng thái treo. - Nút. js phù hợp hơn với các ứng dụng chuyên sâu về I/O, chứ không phải là chuyên sâu về CPU