Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Description for default threads per one nodejs process #4101

Open
ChrisCho-H opened this issue Feb 16, 2023 · 7 comments
Open

Description for default threads per one nodejs process #4101

ChrisCho-H opened this issue Feb 16, 2023 · 7 comments

Comments

@ChrisCho-H
Copy link

ChrisCho-H commented Feb 16, 2023

Details

I'm just wondering whether my understanding is right regarding the default number of thread in nodejs.

1. Without Network I/O

7 threads default per process.

  • 4 threads for LIBUV(fs, zlib, crypto) -> either to execute cpu intensive job(crypto) or File I/O job(because underlying OS does not support async for it)
  • 1 thread for javascript execution
  • 1 thread for garbage collector
  • 1 thread for event loop -> which is mainly used, so nodejs is usually regarded as 1 thread(event loop) per 1 process runtime.

2. With Network I/O

11 threads default per process

  • 7 threads same with above
  • 4 threads for DNS lookup -> which used to share above LIBUV thread pool but separated to solve this issue

Is my understanding right? Any help to correct or elaborate on is welcome!

Node.js version

Latest

Example code

No response

Operating system

MacOS

Scope

runtime

Module and version

Not applicable.

@ChrisCho-H ChrisCho-H changed the title Description for each of default threads per one node process Description for each of default thread per one node process Feb 16, 2023
@ChrisCho-H ChrisCho-H changed the title Description for each of default thread per one node process Description for default threads per one nodejs process Feb 16, 2023
@prettydiff
Copy link

prettydiff commented Feb 16, 2023

No. JavaScript is single threaded and runs (V8) in the same thread as Node.js thereby allowing access to the Node APIs directly to the language without anything crazy. So, there is only one thread.

Asynchronous programming occurs in Node using JavaScript's event model. The event model provides multiple call stacks to this one thread. You have to understand that asynchronous programming is always dramatically slower than synchronous programming (single call stack). The advantage provided by multiple call stacks is that with a single call stack any call to an API for something outside the JavaScript language will freeze the application until that external task completes.

Arguably multiple call stack programming is less powerful than true multi-threading. While tasks outside the actual language may execute and complete in parallel the messaging back to the language must occur in sequence of looping through the event model. With multi-threaded applications everything is truly parallel all the way down and messaging occurs between threads to keep each thread apprised to status changes. Multi-threading, though, requires much greater hardware resources to achieve superior performance though, which is why this matter is arguable.

Node does provide an extended capability for multiple threads though: https://nodejs.org/dist/latest-v19.x/docs/api/cluster.html


EDIT - I failed to address garbage collection.

JavaScript is single threaded and memory is managed internally with garbage collection. There are no options provided for this to the standard language run time. If you read the Node and V8 documentation there might be some command line flag that allows you to customize how garbage collection behaves, but by default memory is completely an unknown black box to the language runtime.

Unfortunately, that means there is a forced performance limitation that you cannot customize. I refer to this as the garbage collection wall, because once you hit it performance grinds to a slow crawl like driving your car into a brick wall. If you write your JavaScript application code like a poor man's C++ application with thousands of isolated tiny classes you are exponentially more likely to encounter this performance limitation.

Garbage collection runs against an offset interval. That means a roughly fixed amount of time after it completed collection it will run again. As a result garbage collection becomes a problem only when the frequency and duration of a given application task exceeds the collector's ability to manage memory according to its frequency of execution. When that does occur memory consumption will occur faster than the garbage collector can reclaim it until the performance wall is hit at which point memory consumption occurs just as fast as the collector can reclaim it with no possibility of recovery.

If instead you accept the foundational design principles of the language you will almost never encounter problems with the garbage collector. Here you go:

  • JavaScript provides lexical scope as the scope mechanism. Embrace this as it is glorious. There are no options.
  • Functions are first class citizens, which means functions can be passed and expressed no differently than a primitive type. That further means functions can be nested without constraint, limitation, or performance implication.
  • JavaScript is single threaded and multi call stack.

Keeping those points in mind if you provide fewer targets for the collector to collect you will almost certainly never encounter the performance penalties associated with garbage collection. Additionally, your code will be better organized and more explicit to read including both syntax and flow control. If you have to guess at how you arrived at a given point in your application or your call stack exceeds 12 steps you have done yourself a horrible disservice.

@ChrisCho-H
Copy link
Author

ChrisCho-H commented Feb 20, 2023

Thanks for elegant explanation for gc and event loop!
However, if you check the process of node, you can find out there are 7 to 12 threads running per 1 node process. I'm just wondering if node is a single thread, what are those other threads running on node?
With this curiosity, I ended up with the conclusion above, single thread for event loop and other complementary threads(not used in most cases).
As I researched, LIBUV has a multi-thread(default size 4) which is clearly declared in its repo!
Description for other threads, here is a reference.
You mean that other threads(i.e. run by LIBUV) are just independent helper for node, so not account as node's thread?

@spaceyTracey50
Copy link

spaceyTracey50 commented Feb 20, 2023 via email

@prettydiff
Copy link

@Hyunhum When I open Windows Task Manager on Windows 10 after starting my Node application I see one entry for Node.js JavaScript Runtime. That process has no child processes associated with it. If were to use the child process library then I would expect to see a sub-process executing with Node as the parent process. Perhaps OS resources are consumed and listed different than what the Task Manager displays and/or other OSs associate low level OS resources in a way that looks like additional processes.

@ivan-kleshnin
Copy link

No. JavaScript is single threaded and runs (V8) in the same thread as Node.js thereby allowing access to the Node APIs directly to the language without anything crazy. So, there is only one thread.

Maybe the last claim is wrong. Macos Activity Monitor also counts 11 or 7 nodejs threads:

Screenshot 2023-09-21 at 09 10 00

For this script:

setTimeout(() => {
  console.log("bye")
}, 60000)

@BoburF
Copy link

BoburF commented Oct 10, 2023

actually there is one thread for v8 and it's call stack with garbage collector(in my opinion), one thread for event loop and there is thread pool with it's default 4 threads.
question: is there 6 threads in nodejs if you use all 4 threads in thread pool?

@RealYukiSan
Copy link

RealYukiSan commented Apr 10, 2024

@Hyunhum When I open Windows Task Manager on Windows 10 after starting my Node application I see one entry for Node.js JavaScript Runtime. That process has no child processes associated with it. If were to use the child process library then I would expect to see a sub-process executing with Node as the parent process. Perhaps OS resources are consumed and listed different than what the Task Manager displays and/or other OSs associate low level OS resources in a way that looks like additional processes.

my mine also not show only 1 thread, here's the output on the linux machine:

$ node -p -e 'require("fs").readFileSync(`/proc/${process.pid}/status`).toString().match(/Threads\W+([0-9]+)/)?.[1]'
7
$ node
Welcome to Node.js v18.19.1.
Type ".help" for more information.
> require("fs").readFileSync(`/proc/${process.pid}/status`).toString().match(/Threads\W+([0-9]+)/)?.[1]
'12'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants