Most of the week was spent developing a client based on Electron.

Electron has a Chrome kernel built in, so it allows us to develop the client like a website.

During development, we ran into a problem that our project needed to load the AI model locally and perform calculations.

Those of you who read my article on browser architecture know that under the current Chrome architecture, the web process is completely separate from the renderer process, so loading the model doesn’t pend the renderer process, so you don’t care.

But it turns out my page is still stuck.

I recorded it using the Performance panel of developer tools. It turned out to be the recognition function after the model was loaded. It was a Promise, a microtask, actually a coroutine, and it was CPU intensive.

Which brings me to my first question:

Does a coroutine pend a process?

To solve this problem, we first have to understand what coroutines are.

What is the process

A process is the smallest unit of system resource allocation. The system consists of a process (program), including text region, data region, and stack region.

  • The text area stores the 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 of the active procedure call.

Therefore, process creation and destruction are relatively expensive operations relative to system resources. A process has three states:

  1. Wait state: waiting for the completion of an event;
  2. Ready state: waiting for the system to allocate the processor to run;
  3. Running state: The possession processor is running.

Processes preemptively compete for the CPU to run itself, and with a single CPU only one process can execute code at a time, but multi-process implementations switch between different processes by the CPU so quickly that it looks like multiple processes are running at the same time.

Communication: Processes are isolated and have their own memory resources. Therefore, they are safer than threads. Therefore, data between processes can be shared only through inter-process Communication (IPC).

What is a thread

  • A thread is a process
  • Threads share the memory address space of a process
  • Thread hardly occupies system resources communication problem: Process is equivalent to a container and the threads run but in the inside of the container, so for the things in the container, the thread is enjoyed together, therefore the communication between threads can communicate through global variables directly, but as a result of multiple threads to read and write, for example, when the same address variable will bring unpredictable consequences, so this time the introduction of various kinds of locks, example Such as mutex.

At the same time multi-threading is not safe, when one thread crashes, it will cause the whole process to crash, that is, other threads also hang, but multi-process does not, one process dies, the other process still runs.

  • A process is the smallest unit of resources allocated by the system
  • Threads are the smallest unit of CPU scheduling
  • Since there is only one thread in the default process, multicore cpus handle multiple processes as if they were one core per process

What is a coroutine

The concept of coroutine is relative to multi-process or multi-thread, he is a cooperative user – state thread

  1. In contrast, threads and processes execute preemptively, meaning that the system automatically switches threads and processes quickly to give us a sense of synchronization. This switching is done automatically by the system
  2. Collaborative say is, want to switch threads, you must be users manual switch coroutines why so fast because, without the system automatically switch (system automatically switching will waste a lot of resources), and coroutines is our user manual switch, and is performed on the same stack, can be very fast and save resources.

However, coroutines have their own problems: coroutines can only have one process, one thread running, and once an IO block occurs, the program freezes.

So before we can use coroutines, we have to make sure that all of our IO is non-blocking. So you need to be asynchronous.

This means that multiple threads collaborate to complete asynchronous tasks.

What does CPU multi-core multithreading refer to

The number of physical CPU cores in a computer is the number of threads that can be parallel at the same time (the CPU can only see threads, threads are the smallest unit of CPU allocation). Thanks to hyperthreading, the number of threads that can actually be parallel is usually twice as many as 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 parallelized, so we refer to the number of cores that the operating system sees, and we refer to the core after hyperthreading (not the physical core).

If the computer has multiple CPU cores, and the total number of threads in the computer less than the number of nuclear, the thread can be run in parallel, in different nuclear if mononuclear multithreading, is not between the multithreaded parallel, but concurrent, namely in order to balance the load, the CPU scheduler will constantly on a single core switch different thread execution, but, as we have said, A core can only run one thread, so concurrency makes it appear that tasks between different threads are executed in parallel, but it actually increases the cost by increasing the overhead of thread switching. If you have multiple cores and multiple threads, and the number of threads is greater than the number of cores, some of those threads will keep switching and executing concurrently, but actually the maximum number of concurrent threads is still the number of cores in the current process, so blindly increasing the number of threads will not make your program faster, but will add extra overhead to your program.

conclusion

From this point of view, coroutines give the thread switching to the code, the user.

The same process can only be executed by one thread at a time, so a single thread of JavaScript will pend the renderer, so the coroutine will also pend the process.

How to solve it?

Since I have a CPU-intensive coroutine that needs to be executed periodically that might pend my current JavaScript thread and then peng the render process, why don’t I find a way to start a separate process to do this?

How does Electron do multiple processes?

If you look through the official documents, you will not find a special multi-process solution, only a multi-thread solution called Web Worker, which I have seen for the first time. If you are interested, you can check the information yourself. It is not difficult to use, and it is not the Electron interface, but JavaScript.

But that doesn’t solve our problem, because it’s another thread, and it doesn’t help if our CPU is single-threaded, we just need another process.

Although there are few computers with single core and single thread, the use of Web Worker requires deep copy of parameters, and the input parameter of this detection tool requires video stream, which cannot be deeply copied and will throw exceptions, so it is not appropriate.

So how do we solve our problem?

In fact, Electron itself is a multi-process architecture. Just like Chrome has a separate render process for each web page on a different site, Electron can do this too. We just need to create a new BrowserWindow and let our detection work in a separate render process. Just send the results to the main renderer through the IPC interface provided by Electron.

Reference links:

Juejin. Cn/post / 684490…