Hai kỹ thuật nhằm ngăn vòng lặp sự kiện (Event Loop) bị chặn khi xử lý tác vụ nặng (CPU-intensive task)

Hai kỹ thuật nhằm ngăn vòng lặp sự kiện (Event Loop) bị chặn khi xử lý tác vụ nặng (CPU-intensive task)

Threads
  • Tuôi" để ý là cứ đợt nào ham đọc cái là lại lười viết, tuần nay tuôi đang đọc một lúc 3 cuốn, à phải là đọc 2 và nghe 1.

    Cuốn sách ám ảnh nhất đến thời điểm hiện tại: Đại dương đen - thuật lại 12 câu chuyện của 12 người mắc bệnh trầm cảm. Thần kinh vững, nhưng mới đọc 2 câu truyện đầu thôi mà cảm giác ngộp thở, bứt rứt thật khó tả 😰

    Câu chuyện tiếp theo đó thì mang lại cảm giác dễ thở hơn vì họ kiểm soát được bản thân. Nhưng sang tiếp câu chuyện thứ 4, thứ 5 thì lại như một có một bàn tay siết họng mình lại. Không thể nhắm mắt mà nghe được á, có gì đó rất đáng sợ.

    Một câu mà mình cảm thấy ám ảnh nhất là khi ba mẹ của người mắc trầm cảm luôn miệng hỏi tại sao con lại như thế mỗi khi sắp lên cơn và gào thét. Họ chỉ đành bất lực trả lời là "Làm sao mà con biết! Cũng giống như hỏi một người bị ốm là tại sao lại ốm? Làm sao mà biết được chứ! Có ai muốn đâu!".

    » Xem thêm
  • Mistral.ai là một công ty AI có trụ sở tại Pháp, được biết đến với nhiều mô hình ngôn ngữ lớn Mistral. Mới đây họ vừa ra mắt thêm một số mô hình có kích thước siêu lớn, siêu mạnh... Nhưng tạm khoan nói đến vì Mistral Chat cũng vừa được ra mắt với nhiều tính năng hay ho tương tự như Chat GPT mà lại miễn phí 😇

    » Xem thêm
  • Qwen2.5-Coder-32B đang là tâm điểm của sự chú ý khi điểm số của nó đánh bại cả GPT-4o hay kể cả là Claude Sonet 3.5. Điều đáng chú ý là nó là mã nguồn mở. Điều đó đồng nghĩa với việc bạn hoàn toàn có thể kéo models về máy và chạy cục bộ dưới máy tính của mình. Nhưng...

    Để chạy được mô hình thì GPU máy tính phải đạt cấp độ quái vật. Cụ thể trong một bài đăng của người dùng thử nghiệm Qwen2.5-Coder-32B trên GTX 3090 thì tốc độ tối đa models cho ra nằm ở mức hơn 30 tokens/s.

    Hy vọng vài nữa sẽ có một bên như Groq hay SambaNova dựng lên để "kiểm thử" hiệu năng con chip của họ, và quan trọng hơn hết là cho anh em dùng "chùa" thì hay biết mấy 🫣

    Tham khảo: Qwen2.5-Coder-32B is an LLM that can code well that runs on my Mac

    » Xem thêm

Vấn đề

Những phép tính phức tạp luôn làm Event Loop đau đầu bởi khi đó nó hoàn toàn bị chặn và gây ra tình trạng máy chủ không phản hồi trong một khoảng thời gian cho đến khi tính toán xong.

Nói vậy thì chẳng phải Node.js chịu thua trước những phép tính như vậy? Bài viết ngày hôm nay tôi xin phép trình bày 2 kĩ thuật để giải quyết một phần vấn đề này.

Partitioning

Hay còn gọi là "phân vùng", phương pháp này dựa trên nguyên lý chia nhỏ số lần thực hiện phép tính để đảm bảo tính luân phiên của Event Loop.

Ví dụ một phép tính trung bình cộng các số từ 1 đến n có độ phức tạp là O(n):

for (let i = 0; i < n; i++)
  sum += i;
let avg = sum / n;
console.log('avg: ' + avg);

Độ phức tạp cũng như chi phí sử dụng CPU sẽ tăng lên nếu như n tăng. Cũng là phép tính đó nhưng nếu áp dụng kĩ thuật Partitioning nó sẽ chia thành n bước không đồng bộ với chi phí thực hiện là O(1):

function asyncAvg(n, avgCB) {
  var sum = 0;
  function help(i, cb) {
    sum += i;
    if (i == n) {
      cb(sum);
      return;
    }

    setImmediate(help.bind(null, i+1, cb));
  }

  help(1, function(sum){
      var avg = sum/n;
      avgCB(avg);
  });
}

asyncAvg(n, function(avg){
  console.log('avg: ' + avg);
});

Partitioning sử dụng setImmediate để tính từng bước của vòng lặp một cách không đồng bộ, điều đó đảm bảo Event Loop sẽ không bị chặn bởi vì setImmediate được thực hiện ở pha "Check". Để tìm hiểu rõ hơn tôi khuyên bạn nên đọc lại bài viết Tìm hiểu về vòng lặp sự kiện (Event Loop) trong node.js. Hiểu một cách đơn giản đó là các phép tính được thực hiện trên mỗi một lần lặp của Event Loop.

Offloading

Nếu bạn làm một điều gì đó phức tạp hơn thì có lẽ Partitioning là chưa đủ. Event Loop chỉ có nhiệm sắp xếp lại thứ tự thực hiện công việc chứ không trực tiếp thực hiện chúng. Nên muốn tận dụng được bộ vi xử lý đa lõi hãy đưa những công việc cần xử lý ra khỏi Event Loop.

Có hai cách để áp dụng Offloading là:

Để tìm hiểu thêm các triển khai Worker Thread các bạn có thể xem bài viết về Worker threads là gì? Bạn đã biết khi nào thì sử dụng Worker threads trong node.js chưa?.

Tổng kết

Đối với các tác vụ đơn giản, như lặp qua các phần tử của một mảng dài tùy ý, Partitioning có thể là một lựa chọn tốt. Nếu logic tính toán của bạn phức tạp hơn, Offloading là một cách tiếp cận tốt hơn.

Kỹ thuật Offloading phải "chi trả" một phần chi phí liên tạc, tức là hành động kết nối giữa các đối tượng được tuần tự hóa giữa Event Loop và Worker Pool nhưng bù lại có thể tận dụng những nhiều lõi tính toán của CPU.

Tuy nhiên, nếu máy chủ của bạn chủ yếu dùng để tính các phép tính phức tạp, bạn nên suy nghĩ về việc liệu Node.js có thực sự phù hợp hay không. Node.js vượt trội đối với tác vụ I/O khhông đồng bộ, nhưng đối với tác vụ nặng về CPU nó có thể không phải là lựa chọn tốt nhất.

Tài liệu tham khảo:

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 (1)

Nội dung bình luận...
Avatar
Gin Na2 năm trước
Phép tính đc thực hiện trên mỗi lần lặp là sao ạ?
Trả lời
Avatar
Gin Na2 năm trước
@gif [3o6Zt6KHxJTbXCnSvu] Cảm ơn ad
Avatar
Xuân Hoài Tống2 năm trước
Bạn đọc lại bài viết&nbsp;https://2coffee.dev/bai-viet/tim-hieu-ve-vong-lap-su-kien-event-loop-trong-nodejs-8 này để biết thêm các event loop hoạt động nhé