线程
什么是线程?
线程是CPU调度的最小单位。而进程是资源分配的最小单位,进程和线程是什么关系?
线程是在进程中的一个执行单位,多进程 本质上开启的这个进程里就有一个线程
多进程 本质上开启的这个进程里就有一个线程
多线程 单纯的在当前进程中开启了多个线程
线程和进程的区别:
线程的开启,销毁,任务切换的时间开销小
在同一个进程中数据共享
能实现并发,但不能脱离进程
进程负责管理分配资源 线程负责执行代码
GIL 锁 ---全局解释器锁
同一时刻只能在有一个线程访问CPU----线程锁
Cpython解释器 ----copy jpython
python程序效率下降
高计算型-----多线程会导致程序的效率下降
高IO型的-----可以使用多线程
多进程
分布式计算-------celery
import time from threading import Thread,currentThread,enumerate,activeCount def func(): print('-->',currentThread()) time.sleep(0.1) print(123) t = Thread(target=func) t.start() print(t.is_alive()) print(t.getName()) t.setName('t1') print(t.getName()) # print(currentThread()) # print(enumerate()) # 你启动的活着的线程数 + 1(主线程) print('-->',activeCount()) # 相当于len(enumerate()) # 守护线程 # 守护进程是等待主进程代码结束之后就结束 # 守护线程是等待主线程都结束之后才结束
import time from threading import Thread,Lock def func(lock): global n temp = n n = temp -1 n = 100 t_lst = [] lock = Lock() for i in range(100): t = Thread(target=func,args=(lock,)) t.start() t_lst.append(t) for t in t_lst:t.join() print(n)
二、同步锁
当多线程争夺锁时,允许第一个获得锁的线程进入临街区,并执行代码。所有之后到达的线程将被阻塞,只到第一个线程执行结束,退出临界区,并释放锁。
多个线程抢占资源的情况:
import time from threading import Thread def func(): global n temp = n time.sleep(1) n = temp -1 n = 100 t_lst = [] for i in range(100): t = Thread(target=func) t.start() t_lst.append(t) for t in t_lst:t.join() print(n)
执行输出:99
明明减少了100次,结果应该是0的。
为啥是99呢?难度是GIL的问题,但GIL是计算CPU那一刻的锁
下面开始具体分析:
第一步,每个线程执行
global n:temp =n 此时,temp等于100
第二步:当线程设计到CPU计算时,向CPU发送请求。但是收到GIL的限制
同一时刻,只能有一个线程计算。
CPU计算结果后,返回给线程。线程赋值,并修改全局变量n。此时n=99,线程结束
那么其他线程,也是做同样的操作。
每个线程赋值n等于99。不管它已经是99了。
上面的现象,出现了数据不安全的情况
最后赋值了100次,都是n=99。所以最终结果是99
怎么解决呢?加锁
import time from threading import Thread,Lock def func(lock): global n lock.acquire() #加锁 temp = n n = temp -1 lock.release() #解锁 n = 100 t_lst = [] lock = Lock() #创建锁 for i in range(100): t = Thread(target=func,args=(lock,)) t.start() t_lst.append(t) for t in t_lst:t.join() #等待所有子线程结束 print(n)
执行输出:0
如果把计算和赋值拆开,就会出现数据不安全的情况
下面写法,不用加锁,也可以得到0
from threading import Thread def func(): global n n -= 1 n = 100 for i in range(100): t = Thread(target=func) t.start()
执行输出:0
因为默认有一个GIL锁,所以每个线程都减等1。所以最终结果为0
三、死锁与递归锁
进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额
所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
1
2
3
4
5
6
|
from threading import Lock lock = Lock() # 在同一个线程中,能够被一个锁的多个acquire阻住,这种锁就叫做互斥锁 lock.acquire() lock.acquire() lock.acquire() |
死锁,也叫互斥锁
科学家吃面的问题
要完成一件事情 需要两个必要因素
要想吃到面,需要: 叉子,面
资源的互相抢占的问题 —— 死锁
四个人围着一张桌子,桌子上放着一碗面,碗里有一个叉子
必须拿到叉子,才能吃面。
每个人每次只能吃一口面,吃完就放回去,让下一个人吃。