In go, threads are entities that run Groutine, and the function of the scheduler is to allocate runnable Groutines to worker threads.
GPM model
There is no absolute quantitative relationship between the number of M and P. When an M is blocked, P will create one or switch to another M, so even if it is set, runtime.GOMAXPROCS(1)
multiple M may be created;
when M finds that it is sending a G coroutine to itself When the P queue is empty, it will actively "steal" from other P queues. The initiator of this process is the coroutine scheduler.
When M is blocked, the P scheduler will release the bound P to the blocked M, and then hand over the P to other M areas for execution;
In order to make greater use of the performance of M and P, the GPM model will not let a P be forever delayed by a blocked G1.
In Go, a coroutine can occupy up to 10ms of CPU. This is to prevent other coroutines from having no CPU available.