一、全局解释器锁--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()