zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    C#客户端和服务端数据的同步传输 (转载)
    静态网页制作教程 (转载)
    C#中将ListView数据导出为excel(转载)
    数据导入Excel时,出现ole error 800AC472这个错误,怎么解决。
    C# 导出dataGridView中的值到Excel
    C#基础知识六之委托(delegate、Action、Func、predicate)
    C#基础知识五之abstract virtual关键字
    C#基础知识四之override和new的区别
    C#基础知识三之new关键字
    C#基础知识二之this关键字
  • 原文地址:https://www.cnblogs.com/xiaowangba9494/p/11353260.html
Copyright © 2011-2022 走看看