python网络编程之GIL和同步锁(二)

Python之GIL

问题:俩程序,在里面同时定义俩函数,执行1到100000的加法和执行100000阶乘,一个程序用多线程,一个正常执行,用python2.7运行(python3.5及以上有优化不明显,python2.7明显),会发现多进程的竟然比正常执行的时间长。
原因:多线程不能真正让多核CPU实现并行,cpython解释器中存在一个GIL(全局解释器锁),他的作用就是保证同一时刻只有一个线程可以执行代码,
因此造成了我们使用多线程的时候无法实现并行。

GIL(全局解释锁):
定义:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。—————>导致了Python不能用来进行高并发。

Python语言和GIL没有半毛钱关系。仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL。

线程释放GIL锁的情况: 在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100。
Python使用多进程是可以利用多核的CPU资源的。
多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁

结论:
1. 在 处理像科学计算 这类(计算密集型)需要持续使用cpu的任务的时候 单线程会比多线程快
2. 在 处理像IO操作(IO密集型)等可能引起阻塞的这类任务的时候 多线程会比单线程

Python之同步锁

下面代码:

import threading
import time
num = 100

def sub():
    global num
    temp = num
    time.sleep(0.0001)
    num = temp - 1

l = []
for i in range(100):
    t = threading.Thread(target=sub)
    t.start()
    l.append(t)

for i in l:
    i.join()
print(num)

运行结果不是猜测的0,而是一个0到100之间的一个不确定数字。
原因:进程使用的是时间片轮转方式切换线程的,当sleep时间大于时间片的时间的话,多个线程取到的数字都是同一个,所以才会出现这种情况。

threading.Lock()方法:
加上同步锁解决:

import threading
import time
num = 100

def sub():
    global num
    lock.acquire()#获得锁
    temp = num
    time.sleep(0.0001)
    num = temp - 1
    lock.release()#释放锁

l = []
lock = threading.Lock()#创建一个锁
for i in range(100):
    t = threading.Thread(target=sub)
    t.start()
    l.append(t)

for i in l:
    i.join()
print(num)

这样运行结果就是0,实质上是给锁中间的代码改成串行的,不让中间代码发生切换。

猜你喜欢

转载自blog.csdn.net/huang_yong_peng/article/details/81844092