个人博客
利用队列Queue实现一个多并发“线程池”效果的Socket程序
线程1:基本概念、线程的基础操作(阻塞与延迟的理解)、多线程与多进程的效率差、数据共享问题、线程的其他方法
线程2:enumerate方法、守护线程、线程锁、死锁现象(递归锁与互斥锁)、线程队列、进程池与线程池
重要概念
GIL——全局解释器锁
GIL的全称是Global Interpreter Lock,
- python中一个线程对应于c语言中的一个线程
- GIL使得同一个时刻只有一个线程在一个cpu上执行字节码, 无法将多个线程映射到多个cpu上执行
- GIL会根据执行的字节码行数以及时间片释放gil, gil在遇到io的操作时候主动释放
GIL的特点
-
Python在多线程下,每个线程的执行方式为:
-
获取GIL
- 执行代码直到sleep或者是python虚拟机将其挂起。
- 释放GIL
一个CPU只能执行一个线程, 例如一个CPU 有三个线程, 首先线程A执行, 然后线程A达到释放条件进行释放GIL, 线程B和线程C进行竞争GIL, 谁抢到GIL, 继续执行.
GIL无法保证线程绝对安全
total = 0
def add():
global total
for i in range(1000000):
total += 1
def desc():
global total
for i in range(1000000):
total -= 1
import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(total)
"""
每一次的结果都不一样!
"""
守护进程
本身是一个子进程。
守护的是“主进程的代码”(就是 if __name__ == '__main__'
下面的代码) —— 正常情况不设置守护进程!
结束条件:主进程的代码结束(主进程的代码结束不代表主进程结束--主进程比主进程代码要长!)!守护进程才结束!
因为守护进程也是一个子进程,他必须在主进程结束之前结束!因此它结束的节点是“主进程代码结束”
具体过程:主进程的代码结束,守护进程结束;主进程要回收子进程的资源;主进程等待其他所有的子进程结束;主进程回收所有子进程的资源!
为什么主进程要等待子进程结束之后才结束?
——因为主进程要负责给子进程回收一些系统的资源