一、全局解释器锁--GIL
在CPython解释器中,进程级别有一把锁,叫做GIL
1、GIL:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。
2、线程释放GIL锁的情况:在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100
3、Python使用多进程是可以利用多核的CPU资源的。
-
多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁
二、同步锁
1、什么是同步锁?
同一时刻的一个进程下的一个线程只能使用一个cpu,要确保这个线程下的程序在一段时间内被cpu执,那么就要用到同步锁。
2、为什么用同步锁?
因为有可能当一个线程在使用cpu时,该线程下的程序可能会遇到io操作,那么cpu就会切到别的线程上去,这样就有可能会影响到该程序结果的完整性。
3、怎么使用同步锁?
只需要在对公共数据的操作前后加上上锁和释放锁的操作即可。
import time import threading R = threading.Lock() def add(): global num R.acquire() # 加锁,保证同一时刻只有一个线程可以修改数据 num -= 1 R.release() # 修改完成就可以解锁 time.sleep(1) num = 100 # 定义一个全局变量 l = [] # 定义一个空列表,用来存放所有的列表 for i in range(100): # for循环100次 t = threading.Thread(target=add) # 每次循环开启一个线程 t.start() # 开启线程 l.append(t) # 将线程加入列表l for i in l: i.join() # 这里加上join保证所有的线程结束后才运行下面的代码 print(num) # 输出结果为0
三、递归锁和死锁
1、什么是递归锁?
在Python中为了支持同一个线程中多次请求同一资源,Python提供了可重入锁。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。
2、什么是死锁?
指两个或两个以上的线程或进程在执行程序的过程中,因争夺资源而相互等待的一个现象.
四、信号量(semaphore)
1、什么是信号量?
semaphore管理一个内置的计数器,每当调用acquire()时内置函数-1,每当调用release()时内置函数+1。
计数器不能为0,当计数器为0时acquire()将阻塞线程,直到其他线程调release()。
import threading import time mysf = threading.Semaphore(5) # 创建信号量对象,(5表示这个锁同时支持的个数) def func(): if mysf.acquire(): # 因为使用了信号量,下面的输出就会5个5个的同时输出 print(threading.currentThread().getName() + 'get semaphore') time.sleep(1) mysf.release() for i in range(20): t = threading.Thread(target=func) t.start()