python并发编程-GIL全局解释锁,Event事件,信号量

一、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.

  ps:python解释器有很多种,最常见的就是Cpython解释器,

  1.GLL本质也是一把互斥锁:将并发变成串行牺牲效率保证数据的安全,用来阻止同一个进程下的多个线程的同时执行(同一个进程内多个线程无法实现并行但是可以实现并发)

  GLL的存在是因为CPython解释器的内存管理不是线程安全的、

  

  2.研究python的多线程是否有需要分情况讨论

cpu/时间/任务 四个任务   计算机密集型  10s 四个任务  IO密集型
单核情况下 开线程更省资源 开线程更节省资源
多核情况下 开进程:10s 
开线程:40s
开线程更节省资源
# 计算密集型
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())  # 本机为6核
    start=time.time()
    for i in range(6):
        # p=Process(target=work) #耗时  4.732933044433594
        p=Thread(target=work) #耗时 22.83087730407715
        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()) #本机为6核
    start=time.time()
    for i in range(4000):
        p=Process(target=work) #耗时9.001083612442017s多,大部分时间耗费在创建进程上
        # p=Thread(target=work) #耗时2.051966667175293s多
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print('run time is %s' %(stop-start))
IO密集型

ps:python的多线程到底有没有用,需要看情况而定,并且肯定是有用的

  多进程+多线程配合使用

 

二、死锁现象

from threading import Thread,Lock,current_thread,RLock
import time
"""
Rlock可以被第一个抢到锁的人连续的acquire和release
每acquire一次锁身上的计数加1
每release一次锁身上的计数减1
只要锁的计数不为0 其他人都不能抢

"""
 mutexA = Lock()
 mutexB = Lock()
# mutexA = mutexB = RLock()  # A B现在是同一把锁


class MyThread(Thread):
    def run(self):  # 创建线程自动触发run方法 run方法内调用func1 func2相当于也是自动触发
        self.func1()
        self.func2()

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

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

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

  用Rlock模块解决问题,定义同一把锁(递归锁)

  Rlock可以被第一个抢到锁的人连续的acquire和release

  每acquire一次锁身上的计数加1

  每release一次锁身上的计数减1

  只要锁的计数不为0 其他人都不能抢

 

三、信号量(互斥锁类似,每轮提供多个位置)

# 信号量可能在不同的领域中 对应不同的知识点
"""
互斥锁:一个厕所(一个坑位)
信号量:公共厕所(多个坑位)
"""
from threading import Semaphore,Thread
import time
import random


sm = Semaphore(5)  # 造了一个含有五个的坑位的公共厕所

def task(name):
    sm.acquire()
    print('%s占了一个坑位'%name)
    time.sleep(random.randint(1,3))
    sm.release()

for i in range(40):
    t = Thread(target=task,args=(i,))
    t.start()
View Code

 

四、event事件

  一个线程等待另一个线程执行信号

  even.set() #发送信号

  even.wait()  # 等待信号

from threading import Event,Thread
import time

# 先生成一个event对象
e = Event()


def light():
    print('红灯正亮着')
    time.sleep(3)
    e.set()  # 发信号
    print('绿灯亮了')

def car(name):
    print('%s正在等红灯'%name)
    e.wait()  # 等待信号
    print('%s加油门飙车了'%name)

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

for i in range(10):
    t = Thread(target=car,args=('伞兵%s'%i,))
    t.start()

 

五、线程queue问题

  同一个进程下的多个线程本来就是数据共享,为什么还要用队列,

  因为队列是管道+锁,使用队列就不需要自己手动操作锁的问题。

  因为锁操作的不好极容易产生死锁现象

  直接 import queue  调用,和进程调用队列有点不同

  方法:

    1.queue.Queue()   # 队列

    2.queue.LifoQueue()  # 堆栈

    3.queue.PriorityQueue()  # 数字越小,优先级越高

      只有一个参数,元组形式

import queue

q = queue.Queue()
q.put('hahha')
print(q.get())


q = queue.LifoQueue()
q.put(1)
q.put(2)
q.put(3)
print(q.get())


q = queue.PriorityQueue()
# 数字越小 优先级越高
q.put((10,'haha'))
q.put((100,'hehehe'))
q.put((0,'xxxx'))
q.put((-10,'yyyy'))
print(q.get())
View Code

 

posted @ 2019-08-14 17:11  小王八+1  阅读(370)  评论(0编辑  收藏  举报