编程知识 cdmana.com

I wrote golang for a year to talk about processes, threads and collaborations

process

In the early days of single task computers , Users can submit only one job at a time , Exclusive access to all resources of the system , At the same time can only do one thing . Calculation cannot be performed IO Reading and writing , but CPU And IO There is a huge difference in the speed of , An assignment is in CPU It takes very little time on , Most of the time waiting IO.

For more rational use CPU resources , Divide memory into blocks , Different programs use their own memory space without interfering with each other , Here, a separate program is a process ,CPU You can switch between multiple processes , Give Way CPU Higher utilization of .

In order to achieve CPU Switch between multiple processes , The context of the process needs to be saved ( Such as program counter 、 Stack 、 Kernel data structure and so on ), So that you can resume execution next time you switch back . We also need a scheduling algorithm ,Linux A completely fair scheduling algorithm based on time slice and priority is adopted .

Threads

The emergence of multiple processes is to solve CPU The problem of utilization , Then why do you need threads ? The answer is to Reduce the overhead of context switching .

The process may give up at the following two time points CPU, Conduct CPU Switch :

  • Process blocking , Such as network congestion 、 Code level blocking ( Like a lock )、 System call, etc
  • Run out of process timeslices , Give up CPU

Process switching CPU You need to do these two steps :

  • Switch page directories to use the new address space
  • Switch between kernel stack and hardware context

Processes and threads are Linux There is no essential difference in , The biggest difference between them is that the process has its own independent memory space , And threads ( In the same process ) Is shared memory space .

The memory address space needs to be converted during process switching , Thread switching does not have this action , So thread switching is less expensive than process switching .

Why is memory address space translation so slow ?Linux In the implementation , The address space of each process is virtual , The conversion from virtual address space to physical address space requires page lookup table , This query is a slow process , Therefore, a method called TLB Of cache To speed up , When the process switches ,TLB It also failed , So it slows down .

Sum up , Threads are used to reduce the overhead during process switching .

coroutines

When our program is IO Intensive time ( Such as web The server 、 Gateway, etc. ), In pursuit of high throughput , There are two ways of thinking :

  1. Open a thread for each request , In order to reduce the overhead of thread creation , You can use thread pool technology , The larger the theoretical online process pool , The higher the throughput , But the larger the thread pool ,CPU The more overhead you spend on switching

Thread creation 、 Destruction requires a system call , Every request creates , It's very expensive to pay high salaries , And the memory occupied by threads is MB Level , Not too many

Why more threads cpu The more you switch ? To be exact, the more threads are executable ,cpu The more you switch , Because the scheduling of the operating system should be absolutely fair , When there are executable threads , It must be wet and wet , So the switching times become more

  1. Use an asynchronous non blocking development model , Receive requests with a process or thread , And then through IO Multiplexing keeps processes or threads from blocking , Save the overhead of context switching

These two options , The advantages and disadvantages are obvious , programme 1 Implement a simple , But the performance is not high ; programme 2 Very good performance , But the implementation is complex . Is there a plan in between ? Be simple , And high performance , Synergy solves this problem .

A coroutine is an abstraction of a user's perspective , The operating system does not have this concept , The main idea is to implement the scheduling algorithm in user state , Scheduling a large number of tasks with a small number of threads .

Coroutines need to solve several problems encountered by threads :

  • Use less memory , And the creation cost is less
  • Reduce the overhead of context switching

The first point is easy to realize , User state concurrency , It's just a data structure , No system calls are required , And it can be designed very small , achieve KB Level .

The second point can only be solved by reducing the number of context switches , Because the essence of coprocessing is still thread , The switching overhead cannot be reduced in the user state , The overall overhead can only be reduced by reducing the number of switches , There can be the following means :

  1. Keep the number of executable threads as small as possible , In this way, the switching times are bound to be less
  2. Keep the thread running as much as possible , Instead of blocking the time slice

Goroutine

goroutine yes golang The process of realization , Its characteristic is that it supports , It is very convenient to use , At its core MPG Scheduling model :

  • M: Kernel thread
  • P: processor , Used to perform goroutine, It maintains local runnable queues
  • G:goroutine, Code and data structures
  • S: Scheduler , maintain M and P Information about

In addition, there is a global runnable queue .

 picture
  1. stay golang Use in go Keyword starts a goroutine, It will be hung to P Of runqueue in , Waiting to be scheduled
 picture
  1. When M0 Is running in G0 Blocking time ( If a system call is executed ), here M0 Will sleep , It will give up the mounted P0, To be used by others M Dispatch to
 picture
  1. When M0 After the system call ends , Will try to “ steal ” One P, If it doesn't work ,M0 take G0 Put it in the overall picture runqueue in

  2. P It will check the global status regularly runqueue, Make sure you digest G There's something to do after , At the same time, it will also learn from other P in “ steal ” G

Judging from the above ,MPG The model seems to only limit the number of threads running simultaneously , But context switching only occurs on runnable threads , It should have a certain effect , Of course, that's only part of it .

golang stay runtime The layer intercepts situations that may lead to thread blocking , And targeted optimization , They can be divided into two categories :

  • The Internet IO、channel operation 、 lock : Just blocking G,M、P You can use , That is, the thread will not give up the time slice
  • system call : Blocking M,P Need to switch , Threads give up time slices

So in general ,goroutine It will cost less than thread switching .

summary

From single process to multi process, it improves CPU utilization ; From process to thread , Reduce the overhead of context switching ; From thread to coroutine , It further reduces the overhead of context switching , So that highly concurrent services can be written in simple code , Every step of technology development is to solve practical problems .


WeChat official account " Master bug catcher ", Back end technology sharing , Architecture design 、 performance optimization 、 Source code reading 、 Troubleshoot problems 、 Step on the pit practice .

 picture

版权声明
本文为[Insect catching master]所创,转载请带上原文链接,感谢
https://cdmana.com/2021/09/20210909124908585i.html

Scroll to Top