操作系统
约 791 字大约 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)等机制.
悲观锁
对并发采取悲观的态度, 在修改数据前先尝试获取锁, 未获取到之前阻塞. 在操作完成后释放锁.