操作系统
约 765 字大约 3 分钟
2024-09-26
提问
- 进程, 线程和协程的区别?
- python 能真正地做到并发吗? 为什么?
- Go 的协程是如何调度的?
- 乐观锁和悲观锁了解吗?
进程, 线程和协程的区别?
进程和线程
进程是资源分配的基本单位, 每个进程都有自己独立的地址空间, 线程是依附于进程存在的,没有独立地址空间。线程是最小的执行单位。 从并发性来说, 线程的并发会好一些。 ( 先别说后面的 ) 并发性好是因为线程的切换无需切换页表, 进程需要切换页表, 会导致 TLB 的命中下降。物理地址和虚拟地址的转换效率变低。 线程的安全性低。因为线程的崩溃会导致这个进程中所有线程全部崩溃, 但是进程的崩溃不会影响其他进程。 线程通信简单。可以在堆上进行通讯, 进程通信需要用到管道, 消息队列, 共享内存。
同一个进程中的各个线程可以共享该进程的所有资源。包括: 虚地址, 已打开文件, 定时器, 信号量等。 但是不能共享进程中某线程的栈指针。
线程和协程
协程是一个用户态的线程。线程的 CPU 信息在内核栈中, 线程的切换需要在内核态中完成。协程的切换在用户态, 调度由用户完成。
协程和 goroutine
goroutine 有一个 GMP 的调度。
python 能真正地做到并发吗? 为什么?
python 无法做到真正的并发。因为它是个脚本语言, 运行过程中编译, 存在 GIL 全局锁的问题。
但是 python 仍然存在 Thread
语法是因为有些任务并非 CPU 密集的, 对于 I/O 密集的任务可以使用多线程编程。
Go 的协程是如何调度的?
G: goroutine P: 资源 M: machine 执行的物理机器
P 和 M 进行绑定后从本地 local 的队列中获取 G, 如果本地队列为空则会从 global 队列中获取或者抢夺其他的 local 队列。
详情请查看 Go 语言中的并发 .
乐观锁和悲观锁
乐观锁和悲观锁是为了解决并发场景下, 多个线程对同一个变量的操作带来的数据一致性问题。
乐观锁
对并发采取乐观的态度, 并不真正加锁. 只在修改数据前检查数据距离自己上一次读取是否被修改过了, 如果没有修改过则进行修改, 如果修改过了则不修改。
判断是否修改过的方法主要有: 版本号和 CAS ( compoare and swap ) 等机制。
悲观锁
对并发采取悲观的态度, 在修改数据前先尝试获取锁, 未获取到之前阻塞。在操作完成后释放锁。