首页 > 其他 > 详细

并发编程——全局解释器锁GIL

时间:2019-05-08 18:11:37      阅读:108      评论:0      收藏:0      [点我收藏+]

1.全局解释器锁GIL

  • GIL其实就是一把互斥锁(牺牲了效率但是保证了数据的安全)。

  • 线程是执行单位,但是不能直接运行,需要先拿到python解释器解释之后才能被cpu执行

  • 同一时刻同一个进程内多个线程无法实现并行,但是可以实现并发

  • 为什么要有GIL是因为它内部的垃圾回收机制不是线程安全的

  • 垃圾回收机制也是一个任务,跟你的代码不是串行运行,如果是串行会明显有卡顿

  • 这个垃圾回收到底是开进程还是开线程?肯定是线程,线程肯定也是一段代码,所以想运行也必须要拿到python解释器

  • 假设能够并行,会出现什么情况?一个线程刚好要造一个a=1的绑定关系之前,这个垃圾线程来扫描,矛盾点就来了,谁成功都不对!

  • 也就意味着在Cpython解释器上有一把GIL全局解释器锁

  • 同一个进程下的多个线程不能实现并行但是能够实现并发,多个进程下的线程能够实现并行

1.python中的多线程到底有没有用?

单核情况下:四个任务

多核情况下:四个任务

计算密集型:一个任务算十秒,四个进程和四个线程,肯定是进程快

IO密集型:任务都是纯io情况下,线程开销比进程小,肯定是线程好

技术分享图片
```python
# 计算密集型
from multiprocessing import Process
from threading import Thread
import os,time
def work():
    res=0
    for i in range(100000000):
        res*=i


if __name__ == __main__:
    l=[]
    print(os.cpu_count())  # 本机为12核
    start=time.time()
    for i in range(12):
        # p=Process(target=work) #耗时8s多
        p=Thread(target=work) #耗时44s多
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print(run time is %s %(stop-start))

# IO密集型
from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
    time.sleep(2)


if __name__ == __main__:
    l=[]
    print(os.cpu_count()) #本机为12核
    start=time.time()
    for i in range(400):
        p=Process(target=work) #耗时12s多,大部分时间耗费在创建进程上
        # p=Thread(target=work) #耗时2s多
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print(run time is %s %(stop-start))
View Code

2.GIL与自定义互斥锁

技术分享图片
不同的数据需要加不同的锁才能保证数据的安全,GIL锁只是对线程加锁,对数据并没有加锁的效果

```python
from threading import Thread,Lock
import time

mutex=Lock()
n=100
def task():
    global n
    with mutex:
        temp=n
        time.sleep(0.1)
        n=temp-1

if __name__ == __main__:
    l=[]
    for i in range(100):
        t=Thread(target=task)
        l.append(t)
        t.start()

    for t in l:
        t.join()
    print(n)
# 对于修改不同的数据,需要加不同的锁进行处理
View Code

3.死锁与递归锁(了解)

自定义锁一次acquire必须对应一次release,不能连续acquire

递归锁可以连续的acquire,每acquire一次计数加一

技术分享图片
from threading import Thread,Lock,RLock
import time

# mutexA=Lock()
# mutexB=Lock()
mutexB=mutexA=RLock()


class Mythead(Thread):
    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        mutexA.acquire()
        print(%s 抢到A锁 %self.name)
        mutexB.acquire()
        print(%s 抢到B锁 %self.name)
        mutexB.release()
        mutexA.release()

    def f2(self):
        mutexB.acquire()
        print(%s 抢到了B锁 %self.name)
        time.sleep(2)
        mutexA.acquire()
        print(%s 抢到了A锁 %self.name)
        mutexA.release()
        mutexB.release()

if __name__ == __main__:
    for i in range(100):
        t=Mythead()
        t.start()
View Code

4.信号量(了解)

自定义的互斥锁如果是一个厕所,那么信号量就相当于公共厕所,门口挂着多个厕所的钥匙。抢和释放跟互斥锁一致

技术分享图片
from threading import Thread,Semaphore
import time
import random
sm = Semaphore(5)  # 公共厕所里面有五个坑位,在厕所外面放了五把钥匙

def task(name):
    sm.acquire()
    print(%s正在蹲坑%name)
    # 模拟蹲坑耗时
    time.sleep(random.randint(1,5))
    sm.release()


if __name__ == __main__:
    for i in range(20):
        t = Thread(target=task,args=(伞兵%s号%i,))
        t.start()
View Code

5.Event事件

一些线程需要等待另外一些线程运行完毕才能运行,类似于发射信号一样

技术分享图片
from threading import Thread,Event
import time
event = Event()  # 造了一个红绿灯


def light():
    print(红灯亮着的)
    time.sleep(3)
    print(绿灯亮了)
    event.set()


def car(name):
    print(%s 车正在等红灯%name)
    event.wait()
    print(%s 车加油门飙车走了%name)


if __name__ == __main__:
    t = Thread(target=light)
    t.start()

    for i in range(10):
        t = Thread(target=car,args=(%s%i,))
        t.start()
View Code

6.线程queue

同一个进程下的线程数据都是共享的为什么还要用queue?queue本身自带锁的功能,能够保证数据的安全

技术分享图片
# 我们现在的q只能在本地使用,后面我们会学基于网络的q 
import queue

queue.Queue() #先进先出
q=queue.Queue(3)
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())

queue.LifoQueue() #后进先出->堆栈
q=queue.LifoQueue(3)
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())

queue.PriorityQueue() #优先级
q=queue.PriorityQueue(3) #优先级,优先级用数字表示,数字越小优先级越高
q.put((10,a))
q.put((-1,b))
q.put((100,c))
print(q.get())
print(q.get())
print(q.get())
View Code

 

 

并发编程——全局解释器锁GIL

原文:https://www.cnblogs.com/guanchao/p/10832930.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!