您的位置:首页 > 产品设计 > UI/UE

DAY 35 GIL全局解释器锁、死锁、递归锁以及event事件与信号量、线程queue

2019-05-08 16:27 375 查看
原文链接:http://www.cnblogs.com/majingjie/p/10832686.html

一.GIL全局解释器锁

"""
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple
native threads from executing Python bytecodes at once. This lock is necessary mainly
because CPython’s memory management is not thread-safe. (However, since the GIL
exists, other features have grown to depend on the guarantees that it enforces.)
"""

  GIL是一个互斥锁:保护数据的安全(以牺牲运行效率来换取数据的安全)

  阻止同一进程内多个线程同时执行(不能并行但是能够实现并发)

  GIL全局解释器锁存在的原因是因为Cpython解释器的内存管理(垃圾处理机制)不是线程安全的

  结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

  1.那么python中多线程是否就没有作用了?

   分情况考虑:

    1.存在四个计算密集型的任务,每个任务耗时10S

    单核情况下:

      多线程好一点,消耗的资源少一点

    多核情况下:

      开四个进程:运行时间10S多一点

      开四个线程:运行时间40S多一点

    2.存在四个IO密集型的任务,每个任务IO 10S

    单核情况下:

      多线程好一点,多进程开启切换的时间较长

    多核情况下:

      多线程好一点,多进程开启切换的时间较长

  总结:多线程和多进程都有自己的优点,要根据项目需求合理选择

  测试结果:

1 # 计算密集型
2 from multiprocessing import Process
3 from threading import Thread
4 import os,time
5 def work():
6     res=0
7     for i in range(100000000):
8         res*=i
9
10
11 if __name__ == '__main__':
12     l=[]
13     print(os.cpu_count())  # 本机为12核
14     start=time.time()
15     for i in range(12):
16         # p=Process(target=work) #耗时8s多
17         p=Thread(target=work) #耗时44s多
18         l.append(p)
19         p.start()
20     for p in l:
21         p.join()
22     stop=time.time()
23     print('run time is %s' %(stop-start))
24
25 # IO密集型
26 from multiprocessing import Process
27 from threading import Thread
28 import threading
29 import os,time
30 def work():
31     time.sleep(2)
32
33
34 if __name__ == '__main__':
35     l=[]
36     print(os.cpu_count()) #本机为12核
37     start=time.time()
38     for i in range(400):
39         p=Process(target=work) #耗时12s多,大部分时间耗费在创建进程上
40         # p=Thread(target=work) #耗时2s多
41         l.append(p)
42         p.start()
43     for p in l:
44         p.join()
45     stop=time.time()
46     print('run time is %s' %(stop-start))
测试结果

二.GIL与普通锁对比

from threading import Thread,Lock
import time

mutex = Lock()

n = 100

def task():
global n
mutex.acquire()
tmp = n
time.sleep(0.1)
n = tmp - 1
mutex.release()

t_list = []
for i in range(100):
t = Thread(target=task)
t.start()
t_list.append(t)

for t in t_list:
t.join()

print(n)

  总结:对于不同的数据,想要保证安全,需要加不同的锁处理

     GIL并不能保证数据的安全,它是对Cpython解释器加锁,针对的是线程安全

     保证的是在同一进程下多个线程之间的安全

三.死锁与递归锁

  死锁现象:

from threading import Thread, Lock
import time

mutexA = Lock()
mutexB = Lock()

class MyThread(Thread):
def run(self):
self.func1()
self.func2()

def func1(self):
mutexA.acquire()
print('%s 抢到了 A锁' % self.name)
mutexB.acquire()
print('%s 抢到了 B锁' % self.name)
mutexA.release()
print('%s 释放了 A锁' % self.name)
mutexB.release()
print('%s 释放了 B锁' % self.name)

def func2(self):
mutexB.acquire()
print('%s 抢到了 B锁' % self.name)
time.sleep(0.1)
mutexA.acquire()
print('%s 抢到了 A锁' % self.name)
mutexB.release()
print('%s 释放了 B锁' % self.name)
mutexA.release()
print('%s 释放了 A锁' % self.name)

for i in range(10):
t = MyThread()
t.start()

  递归锁:

from threading import Thread, RLock
import time

# mutexA = Lock()
# mutexB = Lock()
start = time.time()
mutexB = mutexA = RLock()

class MyThread(Thread):
def run(self):
self.func1()
self.func2()

def func1(self):
mutexA.acquire()
print('%s 抢到了 A锁' % self.name)
mutexB.acquire()
print('%s 抢到了 B锁' % self.name)
mutexA.release()
print('%s 释放了 A锁' % self.name)
mutexB.release()
print('%s 释放了 B锁' % self.name)

def func2(self):
mutexB.acquire()
print('%s 抢到了 B锁' % self.name)
time.sleep(0.1)
mutexA.acquire()
print('%s 抢到了 A锁' % self.name)
mutexB.release()
print('%s 释放了 B锁' % self.name)
mutexA.release()
print('%s 释放了 A锁' % self.name)

for i in range(10):
t = MyThread()
t.start()

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

    递归锁可以连续的acquire,每acquire一次计数+1,只针对第一次抢到的人

四.event事件

from threading import Thread, Event
import time

event = Event()

def light():
print('红灯亮')
time.sleep(5)
event.set() # 给event发信号,解除阻塞
print('绿灯亮')

def car(i):
print('车%s is stop' % i)
event.wait() # 阻塞
print('车%s is run' % i)

l = Thread(target=light)
l.start()

for i in range(10):
c = Thread(target=car,args=(i,))
c.start()

五.信号量

from threading import Thread, Semaphore
import time
import random

sm = Semaphore(5) # 五个厕所五把锁

# 跟你普通的互斥锁区别在于,普通的互斥锁是独立卫生间,所有人抢一把锁
# 信号量 公共卫生间 有多个坑,所有人抢多把锁

def wait(name): with sm: print('%s is WCing' % name) time.sleep(random.randint(1,5)) for i in range(10): t = Thread(target=wait,args=(i,)) t.start()  

五.信号量

import queue

# 1.普通q
# 2.先进后出q
# 3.优先级q

# 1.普通q
q = queue.Queue(3)
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())

# 先进后出q
q = queue.LifoQueue(5)
q.put(1)
q.put(2)
q.put(3)
q.put(4)
print(q.get())

# 优先级q
q = queue.PriorityQueue()
q.put((10, 'a'))
q.put((-1, 'b'))
q.put((100, 'c'))
print(q.get())
print(q.get())
print(q.get())

 

  

 

转载于:https://www.cnblogs.com/majingjie/p/10832686.html

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐