3

I would like to clarify my understanding of kernel threads and user threads in a multicore environment .

Only threads created by the kernel can run on different cores of a cpu ,if the cpu supports it . The user level threads are abstracted on a single core by libraries , and hence, all user level threads run on the same core .

Python threads can run only one at a time because they need to hold the GIL , so irrespective of the implementation of python threads , only 1 core can be used at a time in a multicore environment .

In nodejs there is a main thread called eventloop that handles all the core processing . All io related activities are offloaded to worker threads . But modern computers do not use the cpu for io activities , and rather offload the io activities to the io controllers . So the so called worker threads are really just an abstraction for offloading io activities to the io controller . No real thread is being created .

Hence neither a python nor a nodejs program can truly use more than one core at a time in a multicore environment .

Am I getting this right ?

Saurav Jha
  • 33
  • 1
  • 6

2 Answers2

6

I am intimately familiar with neither Python nor Node.js, but I can help you out with the rest.

In my estimation, the easiest way to understand user threads is to understand how the kernel manages (kernel) threads in a single-core system. In such a system, there is only one hardware thread, i.e. only one thread can physically be in execution on the CPU at any given time. Clearly, then, in order to run multiple threads simultaneously, the kernel needs to multiplex between the threads. This is called time sharing: the kernel juggles between threads, running each for just a bit (usually in the order of, say, 10 ms) before changing to another thread. The time quantum given to each process is short enough so that it appears that the threads are being run in parallel, while in reality they are being run sequentially. This kind of apparent parallelism is called concurrency; true parallelism requires hardware support.

User threads are just the same kind of multiplexing taken one step further.

Every process initially starts with only one kernel thread, and it will not get more unless it explicitly asks the kernel. Therefore, in such a single-threaded process, all code is executed on the same kernel thread. This includes the user-space threading library responsible for creating and managing the user threads, as well as the user threads themselves. Creating user threads doesn't result to kernel threads being created - that is exactly the point of user-space threads. The library manages the user threads created by itself in much the same way that the kernel manages kernel threads; they both perform thread scheduling, which means that user-threads, too, are run in turns for a short time, one at a time.

You'll notice that this is highly analogous to the kernel thread scheduling described above: in this analogy, the single kernel thread the process is running on is the single core of the CPU, user threads are kernel threads and the user-space threading library is the kernel.

The situation remains largely the same if the process is running on multiple kernel threads (i.e. it has requested more threads from the kernel via a system call). User threads are just data structures local to the kernel thread they are run on, and the code executed on each user thread is simply code executed on the CPU in the context of the kernel thread; when a user thread is switched to another, the kernel thread essentially performs a jump and starts executing code in another location (indicated by the user thread's instruction pointer). Therefore, it is entirely possible to create multiple user threads from multiple kernel threads, although this would pretty much defeat the purpose of using user threads in the first place.

Here is an article about multithreading (concurrency) and multiprocessing (parallelism) in Python you might find interesting.

Finally, a word of warning: there is a lot of misinformation and confusion regarding kernel threads floating around. A kernel thread is not a thread that only executes kernel code (and threads executing kernel code aren't necessarily kernel threads, depending on how you look at it).

I hope this clears it up for you - if not, please ask for clarification and I'll try my best to provide it.

0x4d45
  • 704
  • 1
  • 7
  • 18
  • Thank you ihonen, have few questions. 1.) Can you brief what exactly is the job of kernel thread ? 2.) Who decides when kernel thread needs to be created ? 3.) Why do we need kernel thread context to execute user threads, why not directly user level threads ? – stonelazy May 18 '21 at 08:36
  • 1
    @stonelazy 1) The kernel may stop any thread at any time and start running another. The job of the kernel thread is to store the execution context of the stopped thread and to help implement CPU scheduling. 2) One kernel thread is created whenever a process is spawned - it is then up to each process to request the kernel to create more if needed. 3) The kernel is only aware of kernel threads, so in order for a thread to be scheduled for execution (i.e. actually be run on the CPU), it has to be a kernel thread. So your process must have at least one kernel thread - otherwise it's not a process. – 0x4d45 May 18 '21 at 17:57
1

Nodejs as a main thread as you said, which will execute all the javascript code.

For all I/O execution such as fs or dns which cost more, the libuv used by nodejs will offload the work to different thread. If the threads number in the pool is larger than the cores number you have on your machine, the resources of your machine will be divided.

At the end, I/O will use the different core cpu you have available.

here an article about that

If you want to take advantage of the different core of your machine for you application, you will have to use a cluster where you can find the api there

Hope i answered your question

Adrien De Peretti
  • 3,342
  • 16
  • 22