thảo luận Câu hỏi phỏng vấn - làm sao nodejs chạy với 1 thread?

  • Người tạo chủ đề Người tạo chủ đề hoctrokha
  • Ngày bắt đầu Ngày bắt đầu

hoctrokha

Senior Member
Mình đã phỏng vấn khá nhiều ứng viên về cả backend lẫn frontend trong nhiều năm, chỉ có 1 câu hỏi mà gần như không có bạn nào trả lời đúng cả, đó là:
Nếu nodejs là single threaded, vậy tại sao nó có thể gọi 1 http api bằng await, đợi http api đó trả lời rồi tiếp tục chạy code phía sau dòng await.

Tại khi await thì thread sẽ chạy đi làm việc khác, vậy cái gì ngồi đó đợi cái http request đó?

Câu trả lời mình thường nhận được là: cái event loop nó, nó loop đi loop lại để check xem cái http request đó xong chưa.

Ok, nhưng nếu cái event loop đó cứ loop đi loop lại để check cái request đó xong chưa, vậy thì phải có cái gì đó khác chạy ở bên dưới để đợi các network request rồi báo cho event loop là network request đó xong rồi chứ đúng không?

Ứng viên thường trả lời: Ừ chắc đúng vậy, nodejs bên trên là JS nên dùng event loop, bên dưới runtime của nodejs phải có multitask/multi thread mới xử lý được.
Câu trả lời này sai, JS runtime ko có dùng thêm thread nào cả.
Kể cả bạn có hỏi AI thì câu trả lời chắc chắn vẫn quá nông và không nói được bản chất vấn đề, bởi OS cũng là phần mềm, nó vẫn phải dùng CPU thôi.


1780886647374.webp

1780888283024.webp


Lý do mình post câu hỏi này lên đây bởi đây không chỉ là vấn đề của nodejs, mà là cách máy tính vận hành nói chung. Dev viết code nhưng không hiểu code bên dưới chạy như nào. Câu hỏi này cũng áp dụng cho mọi ngôn ngữ khác, bởi nó là bản chất cách máy tính hoạt động.
Tuy nhiên, mình cũng không mong đợi dev trả lời đúng, đây chỉ là 1 câu hỏi xem dev có kiến thức về low level software hay ko thôi, trả lời được thì mình đánh giá rất cao, còn k trả lời được thì mình coi như chưa hỏi, ko sao cả.

Câu trả lời đúng là: Không có cái gì từ phía CPU ngồi đợi cái http request đó cả. Việc xử lý và thông báo kết qủa http request được xử lý ở mức phần cứng, cái card mạng báo cho CPU là việc CPU giao cho nó đã xong, nó bắn một message cho CPU để báo rằng nó đã xong việc, cpu báo với OS, OS báo lại với nodejs.

Nói chung là vậy, câu trả lời trên hơi sơ sài, nhưng để hiểu và trả lời được vậy thì phải hiểu được một nùi thứ từ phía phần cứng + hệ điều hành.
Mình post câu hỏi này lên đây để cho mọi người suy nghĩ, bởi không sớm thì muộn, bạn sẽ đụng phải các khái niệm low level như stack, heap, context switch ...
Có chút kiến thức về low level software sẽ rất tốt cho mọi người.
Cháu mình chắc năm sau vào đại học, có lẽ cái đầu tiên mình dạy nó sẽ là mấy cái cơ bản này.

Tiện đây share với các bạn 1 kênh youtube rất hay mình kiếm được, ông này giải thích rất tốt về các khái niệm bên trên, hy vọng sẽ giúp ích cho mọi người.
 
JS runtime ko có dùng thêm thread nào cả.
Cái này mới sai nè, JS runtime dùng hơn 1 thread nhé thím
veP4TpD.gif


Node là 1 runtime của JS, và Node có 1 thứ gọi là libuv, chính thằng này sẽ đảm nhận việc offload các I/O intensive tasks.
Vì JS là single-threaded non-blocking nên JS sẽ chỉ có 1 main thread để xử lý thôi nhưng không có nghĩa là Node nó không xài thêm thread nào khác.

FYI: Thread pool work scheduling - libuv documentation (https://docs.libuv.org/en/stable/threadpool.html)
 
Sửa lần cuối:
Nếu nodejs là single threaded, vậy tại sao nó có thể gọi 1 http api bằng await, đợi http api đó trả lời rồi tiếp tục chạy code phía sau dòng await.

Tại khi await thì thread sẽ chạy đi làm việc khác, vậy cái gì ngồi đó đợi cái http request đó?
Chỗ này là do thím không đọc kĩ docs của nó th.
Trong lúc đang execute task trong task queue của NodeJS, nếu có bất cứ thứ gì dính tới I/O thằng node sẽ offload nó qua libuv - đi kèm với một callback khi cái I/O đó đã xong.

Và một khi I/O đó xong, callback sẽ được enqueue vào trong poll queue, NodeJS event loop nếu chạy tới poll phase sẽ dequeue từng callback ra và ném vô lại trong task queue để xử lý (no-blocking là ở đoạn này), cho tới khi nào poll queue rỗng hoàn toàn.
dv67XHR.jpeg


còn vấn đề await thì thím nên nhớ nó chỉ là một sugar syntatix của JS, bản chất nó vẫn là callback.
Ví dụ:
JavaScript:
const response = await fetch()
console.log("Done")

// Tương đương với

fetch.then(() => {
    console.log("Done") // Callback sẽ được enqueue khi network call hoàn thành, và sẽ được xử lý bởi JS main thread khi tới poll phase
})
 
Câu trả lời đúng là: Không có cái gì từ phía CPU ngồi đợi cái http request đó cả. Việc xử lý và thông báo kết qủa http request được xử lý ở mức phần cứng, cái card mạng báo cho CPU là việc CPU giao cho nó đã xong, nó bắn một message cho CPU để báo rằng nó đã xong việc, cpu báo với OS, OS báo lại với nodejs.
phần này là phần thằng libuv cũng là 1 phần của nodejs handle còn gì nữa, như default thì thằng libuv nó dùng 4 thread
 
Cái này mới sai nè, JS runtime dùng hơn 1 thread nhé thím
veP4TpD.gif


Node là 1 runtime của JS, và Node có 1 thứ gọi là libuv, chính thằng này sẽ đảm nhận việc offload các I/O intensive tasks.
Vì JS là single-threaded non-blocking nên JS sẽ chỉ có 1 main thread để xử lý thôi nhưng không có nghĩa là Node nó không xài thêm thread nào khác.

FYI: Thread pool work scheduling - libuv documentation (https://docs.libuv.org/en/stable/threadpool.html)
Ý mình k có nói JS runtime là single threaded. Ý mình nói là khi 1 network request được gọi, runtime nó k có spaw ra 1 thread để đợi cái request đó. Nodejs xử lý 1000 db call, không có nghĩa nó cần 1000 thread ngồi đợi.
Với disk I/O thì khác, libuv sẽ lấy 1 thread từ pool để đợi, nhưng nhìn chung là một trong các edge case mà nodejs dùng thread để optimize.

Nói cách khác, không có chuyện nodejs có 1 thread ngồi đợi network request của bạn, cái network card sẽ phải wake up ngược lên nodejs. Disk I/O thì hoạt động khác nên mới cần đến 4 cái thread của libuv.
 
Sửa lần cuối:
Ý mình k có nói JS runtime là single threaded. Ý mình nói là khi 1 network request được gọi, runtime nó k có spaw ra 1 thread để đợi cái request đó. Nodejs xử lý 1000 db call, không có nghĩa nó cần 1000 thread ngồi đợi.
Với disk I/O thì khác, libuv sẽ lấy 1 thread từ pool để đợi, nhưng nhìn chung là một trong các edge case mà nodejs dùng thread để optimize.
Cái này là cơ bản của non-blocking mechanism, không phải riêng gì của NodeJS đâu thím.
Java cũng có thứ tương tự đó
Pd665Bh.png
 
phần này là phần thằng libuv cũng là 1 phần của nodejs handle còn gì nữa, như default thì thằng libuv nó dùng 4 thread
Xem câu trả lời trên của mình nhé b, 4 thread đó chỉ apply cho disk I/O, ko phải cho network I/O.
 

nhớ xưa voz cũng có 1 thớt
 

nhớ xưa voz cũng có 1 thớt
Hmm, 2 câu hỏi này khác nhau mà b. Câu hỏi kia là liệu nodejs có phải single thread hay ko?
Còn câu hỏi này là làm sao có 1 thread mà nodejs có thể handle hàng ngàn network activity cùng 1 lúc?
Câu hỏi này không chỉ giới hạn ở nodejs, nó apply cho tất cả các phần mềm chạy trên các loại máy tính phổ thông nói chung.
 
Mình đã phỏng vấn khá nhiều ứng viên về cả backend lẫn frontend trong nhiều năm, chỉ có 1 câu hỏi mà gần như không có bạn nào trả lời đúng cả, đó là:
Nếu nodejs là single threaded, vậy tại sao nó có thể gọi 1 http api bằng await, đợi http api đó trả lời rồi tiếp tục chạy code phía sau dòng await.

Tại khi await thì thread sẽ chạy đi làm việc khác, vậy cái gì ngồi đó đợi cái http request đó?

Câu trả lời mình thường nhận được là: cái event loop nó, nó loop đi loop lại để check xem cái http request đó xong chưa.

Ok, nhưng nếu cái event loop đó cứ loop đi loop lại để check cái request đó xong chưa, vậy thì phải có cái gì đó khác chạy ở bên dưới để đợi các network request rồi báo cho event loop là network request đó xong rồi chứ đúng không?

Ứng viên thường trả lời: Ừ chắc đúng vậy, nodejs bên trên là JS nên dùng event loop, bên dưới runtime của nodejs phải có multitask/multi thread mới xử lý được.
Câu trả lời này sai, JS runtime ko có dùng thêm thread nào cả.
Kể cả bạn có hỏi AI thì câu trả lời chắc chắn vẫn quá nông và không nói được bản chất vấn đề, bởi OS cũng là phần mềm, nó vẫn phải dùng CPU thôi.


Xem tệp đính kèm 3653639
Xem tệp đính kèm 3653711

Lý do mình post câu hỏi này lên đây bởi đây không chỉ là vấn đề của nodejs, mà là cách máy tính vận hành nói chung. Dev viết code nhưng không hiểu code bên dưới chạy như nào. Câu hỏi này cũng áp dụng cho mọi ngôn ngữ khác, bởi nó là bản chất cách máy tính hoạt động.
Tuy nhiên, mình cũng không mong đợi dev trả lời đúng, đây chỉ là 1 câu hỏi xem dev có kiến thức về low level software hay ko thôi, trả lời được thì mình đánh giá rất cao, còn k trả lời được thì mình coi như chưa hỏi, ko sao cả.

Câu trả lời đúng là: Không có cái gì từ phía CPU ngồi đợi cái http request đó cả. Việc xử lý và thông báo kết qủa http request được xử lý ở mức phần cứng, cái card mạng báo cho CPU là việc CPU giao cho nó đã xong, nó bắn một message cho CPU để báo rằng nó đã xong việc, cpu báo với OS, OS báo lại với nodejs.

Nói chung là vậy, câu trả lời trên hơi sơ sài, nhưng để hiểu và trả lời được vậy thì phải hiểu được một nùi thứ từ phía phần cứng + hệ điều hành.
Mình post câu hỏi này lên đây để cho mọi người suy nghĩ, bởi không sớm thì muộn, bạn sẽ đụng phải các khái niệm low level như stack, heap, context switch ...
Có chút kiến thức về low level software sẽ rất tốt cho mọi người.
Cháu mình chắc năm sau vào đại học, có lẽ cái đầu tiên mình dạy nó sẽ là mấy cái cơ bản này.

Tiện đây share với các bạn 1 kênh youtube rất hay mình kiếm được, ông này giải thích rất tốt về các khái niệm bên trên, hy vọng sẽ giúp ích cho mọi người.
“nó bắn một message cho CPU để báo rằng nó đã xong việc“

Bắn message là sao? Có thiệt là cha hiểu low level không?
Rồi CPU nào báo lại cho OS thế nào? Cũng là bắn message? Vậy message đó bao hàm những gì?
 
Câu trả lời đúng là: Không có cái gì từ phía CPU ngồi đợi cái http request đó cả. Việc xử lý và thông báo kết qủa http request được xử lý ở mức phần cứng, cái card mạng báo cho CPU là việc CPU giao cho nó đã xong, nó bắn một message cho CPU để báo rằng nó đã xong việc, cpu báo với OS, OS báo lại với nodejs.
Nói thôi không phải chửi đâu chứ bro giải thích nghe nó fking weird á, tôi không nghĩ cái card mạng nó xử lý công việc ở tầng Application của OSI model đâu (Http request)
 
Sửa lần cuối:
ko biết gì, nhưng đọc comment thì tức là ông thớt cũng hiểu sai vấn đề nhưng lại đi phỏng vấn sâu về cái vấn đề đấy à, người phỏng vấn mà như thế thì nguy hiểm nhỉ :cautious:
 
“nó bắn một message cho CPU để báo rằng nó đã xong việc“

Bắn message là sao? Có thiệt là cha hiểu low level không?
Rồi CPU nào báo lại cho OS thế nào? Cũng là bắn message? Vậy message đó bao hàm những gì?
Mình đâu phải AI đâu mà giải thích cho b từng cái một. Mình cho b câu hỏi, bạn tự tìm câu trả lời, có j ko hiểu thì hỏi t giải thích.
Có thật là người phỏng vấn không vậy, card mạng nào xử lý request??? OS hay chính xác hơn là kernel làm điều đó nhé :), rồi phân biệt dùm JS và JS runtime dùm cái@@
Kernel cũng là phần mềm thôi chứ có phải phần cứng đâu mà đòi xử lý.

yes, em cũng nghĩ như bác. Sao lại card mạng xử lí request đc, nghe cứ sai sai
Cuối cùng nó cũng về tầng network thôi, k về card mạng thì đi đâu?


Nói thôi không phải chửi đâu chứ bro giải thích nghe nó fking weird á, tôi không nghĩ cái card mạng nó xử lý công việc ở tầng Application của OSI model đâu (Http request)
Yeah, nó weird bởi t nói tóm tắt quá, nhưng bạn có thể hiểu là request http hay gì đi nữa thì cuối cùng nó cũng chạy ra card mạng để xử lý thôi.
ko biết gì, nhưng đọc comment thì tức là ông thớt cũng hiểu sai vấn đề nhưng lại đi phỏng vấn sâu về cái vấn đề đấy à, người phỏng vấn mà như thế thì nguy hiểm nhỉ :cautious:
Hay thật, bạn ko biết gì, nhưng đọc comment lại nghĩ t hiểu sai vấn đề? Bạn tin 1 phía trong khi họ k có evidence, bạn cũng k muốn đi verify/tìm hiểu và tin họ luôn?
Nếu bây giờ họ bảo nodejs nói chuyện trực tiếp với card mạng để gửi request chắc bạn cũng tin luôn nhỉ?
 
Câu trả lời đúng là: Không có cái gì từ phía CPU ngồi đợi cái http request đó cả. Việc xử lý và thông báo kết qủa http request được xử lý ở mức phần cứng, cái card mạng báo cho CPU là việc CPU giao cho nó đã xong, nó bắn một message cho CPU để báo rằng nó đã xong việc, cpu báo với OS, OS báo lại với nodejs.
Đang làm nhúng, mấy cái low level, multicore, multi task/thread mà đọc câu trả lời mà mắc ói =((
Làm trên Linux hay Win x86 thì liên quan đầy đến userpsace, rồi nào system call, interrupt, nested interupt, message queue bla bla.

Ông nội thớt chắc éo biết http/https được handle ra sao trong mô hình OSI, rồi cái "card mạng" làm cái gì để transfer từ ethernet packet, ip packet, network packet tới applicatio packet (trong trường hợp này là http). Tóm lại sai bét.
 
Bữa nay mở ra đọc comment thì thấy các bạn hỏi những câu rất khó hiểu, một phần vì mình nói tóm tắt quá. Nhưng cũng không ngờ đc các bạn ko hiểu nếu như t nói tóm tắt như vậy.

Các comment thường là: "NIC ko xử lý request, kernel mới là chỗ xử lý". Ờ thì cũng đúng, nhưng nếu nói theo cách bắt bẻ từng chữ thì kernel cũng đâu có xử lý http request, nó xử lý tcp/ip connection mà. Rồi ba bữa nữa nếu một O/S nào đó cho http vào kernel của nó luôn thì các bạn lại đi cãi nhau xem thằng nào xử lý "request" à? Túm lại, bọn này là software, ko phải hardware, thằng nào xử lý cái gì cũng vậy thôi.
Bắt buộc phải có cái gì đó bên dưới thông báo cho nó rằng network package đã gửi/nhận xong.

Http hay gì thì cuối cùng nó cũng sẽ quay về việc gửi và nhận các network package, và việc làm sao O/S của bạn biết được 1 network package đã được nhận/gửi nó phải đến từ NIC.
NIC phải thông báo cho CPU biết rằng nó xong việc bằng cách báo cho CPU biết thông qua PCIE, qua đó mới có thể tiếp tục xử lý ở các tầng cao hơn.
 

Thống kê chủ đề

Ngày tạo
hoctrokha,
Người trả lời cuối
Có Ai Xúi Giục Em Không,
Trả lời
219
Lượt xem
21.470
Quay lại
Lên đầu trang