Electron Multi-Process Scheme

Most of this week has been spent developing an Electron-based client.

Electron has a built-in chrome kernel, so it allows us to develop clients like a website.

During the development process, we encountered a problem that our project needed to load AI models locally and perform calculations.

Have seen my introduction浏览器结构那篇文章You should know that under the current chrome structure, the network process and the rendering process are completely separate, so loading the model will not pend the rendering process, so I don’t care.

But it turns out that my page still has cards.

So I recorded it with the Performance panel of the developer tools, and it was found that it was the recognition function after the model was loaded. It was a Promise, a microtask, and actually a coroutine, and it was a CPU-intensive coroutine.

So here comes my first question:

Will the coroutine pending the process?

To solve this problem, we must first understand what a coroutine is.

What is the process

Process is the smallest unit of system quota, the system consists of a process (program), in general, including text area (text region), data area (data region) and stack (stack region).

  • Text area stores code executed by the processor
    The data area stores variables and dynamically allocated memory used during process execution.
  • The stack area stores the instructions and local variables for the active procedure call.

Therefore, the creation and destruction of processes are relative to system resources, so it is a relatively expensive operation. Processes have three states:

  1. Waiting state: waiting for the completion of an event;
  2. Ready state: waiting for the system to allocate a processor to run;
  3. Running state: occupies that the processor is running.

Processes compete preemptively for the CPU to run itself, while in the case of CPU core solo, only one process can execute the code at the same time, but the implementation of multi-process is to switch between different processes quickly through the CPU, so it looks like multiple Processes are running at the same time.

Communication issues:

What is a thread

  • Threads belong to processes
  • Threads share the memory address space of the process
  • Threads hardly occupy system resources, communication problems: the process is equivalent to a container, and the thread runs in the container, so for the things in the container, the thread is shared, so the communication between threads can be directly through global variables Communication, but the resulting results, such as when multiple threads read and write the same address variable, will bring unexpected consequences, so the role of various locks is introduced at this time, such as mutual exclusion.

At the same time, multi-threading is unsafe. When one thread crashes, it will cause the entire process to crash, that is, other threads also hang up, but multi-process will not. If one process hangs up, another process will still run as usual.

  • *** Process is the smallest unit of system allocation of resources ***
  • *** Thread is the smallest unit of CPU scheduling ***
    • Since there is only one thread in the default process, multi-core CPUs handle multiple processes like one process with one core *

What is a coroutine

The concept of coroutine is relative to multi-process or multi-threading. It is a collaborative User Mode thread

  1. In contrast, threads and processes are preemptively executed, which means that the system helps us automatically switch threads and processes quickly to make us feel synchronized. This switching action is automatically completed by the system
  2. Cooperative execution means that if you want to switch threads, you must have the user switch manually. The reason why the coroutine is so fast is because there is no need for automatic system switching (automatic system switching will waste a lot of resources), and ** coroutine It is our user’s manual switching **, and it is executed on the same stack, which will be very fast and save resources.

However, coroutines have their own problems: coroutines can only have one process, one thread running, and once IO blocking occurs, the program will get stuck.

So before we use coroutines, we must ensure that all of our IO must be non-blocking. That is, asynchronous.

It means that multiple threads cooperate with each other to complete Asynchronous Tasks.

What does multi-core and multi-threading of CPU mean?

The number of cpu physical cores of a computer is the number of threads that can be parallel at the same time (cpu can only see threads, threads are the smallest unit of cpu scheduling allocation). Due to hyperthreading technology, the number of threads that can actually be parallel is usually twice the number of physical cores, which is also the number of cores seen by the operating system. We only care about the number of threads that can be parallel, so the number of cores mentioned later is the number of cores seen by the operating system, and the core referred to is also the core (not the physical core) after hyperthreading technology.

If the computer has multiple cpu cores, and the total number of threads in the computer is less than the number of cores, threads can run in parallel in different cores. If it is core solo multithreading, then the multithreads are not parallel, but Concurrency, that is, in order to balance the load, the cpu scheduler will constantly switch different threads on the core solo for execution, but we have said that a core can only run one thread, so although concurrency makes us look like tasks between different threads are executed in parallel, but in fact it is more expensive due to the increased overhead of thread switching If it is multi-core multi-threading, and the number of threads is greater than the number of cores, some of them will continue to switch and execute concurrently, but in fact the maximum number of parallel or the number of cores in the current process, so blindly increasing the number of threads will not only make your program faster, but will add extra overhead to your program.

Conclusion

From this perspective, coroutines actually give the right to switch threads to the code, that is, the user.

Only one thread can execute the same process at the same time, so a single thread in JavaScript will pend the rendering process, so the coroutine will actually pend the process.

How to solve it?

Since I have a CPU-intensive coroutine that needs to be executed regularly, it may pause my current JavaScript thread and then pause the rendering process, why don’t I find a way to open a separate process to perform this task?

How does Electron handle multiple processes?

If you go to read the official doc, you will not find a special multi-process solution. There is only a multi-threaded solution called ** Web Worker **. This is the first time I have seen it. If you are interested, you can check the information yourself. It is not difficult to use, nor is it the interface of Electron, but provided by JavaScript.

But this does not solve our problem, because it is to open another thread, if our CPU is core solo single-threaded, and there is no use, we need to open another process.

Although we rarely have computers that are core solo single-threaded, the use of Web Workers requires deep copying of parameters, and the imported parameters of this detection tool require video streaming, which cannot be deeply copied and will throw exceptions, so Not suitable.

So how do we solve our problem?

In fact, Electron itself is a multi-process architecture, just like Chrome will be a separate rendering process for each web page of different stations, Electron can also do it, we only need a new BrowserWindow on it, and then let Our detection task works in a separate rendering process, and the results are sent to the main rendering process through the IPC communication interface provided by Electron.

Reference link:

https://juejin.cn/post/6844903607892967432