• 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.

    在Cpython中,GIL这个全局解释器锁就是一个互斥锁,一次只能让一个线程运行。这把锁是必须且重要的是因为Cpython解释器的内存管理对线程来说并不是一个安全的。

    然而,自从GIL存在,其他特性已经成长为依赖于它强制执行的保证。(就是所有的线程都要去抢这把锁)

    假设没有GIL这把锁的情况下,会出现的情况!!!

    * 为什么要有GIL是因为它内部的垃圾回收机制不是线程安全的
    * 垃圾回收机制也是一个任务,跟你的代码不是串行运行,如果是串行会明显有卡顿
    * 这个垃圾回收到底是开进程还是开线程?肯定是线程,线程肯定也是一段代码,所以想运行也必须要拿到python解释器
    * 假设能够并行,会出现什么情况?一个线程刚好要造一个a=1的绑定关系之前,这个垃圾线程来扫描,矛盾点就来了,谁成功都不

     

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

    单核情况下:四个任务

    多核情况下:四个任务

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

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

     

    import os,time
    from multiprocessing import Process
    from threading import Thread
    
    '''
    def work():
        res=0
        for i in range(100000000):#做的是计算型的操作
            res*=i
    
    if __name__ == '__main__':
        l=[]
        print(os.cpu_count())  #8
        start=time.time()
        for i in range(8):#产生8个进程同时执行
            p=Thread(target=work)#run time is 39.95239758491516
            # p=Process(target=work)  #run time is 8.076356410980225
            l.append(p)
            p.start()
        for p in  l:
            p.join()
        stop=time.time()
        print('run time is %s'%(stop-start))
    '''
    #io密集型
    def work():
        time.sleep(2)
    
    if __name__ == '__main__':
        start=time.time()
        l=[]
        for i in range(600): #开启600个线程
            p=Process(target=work) #run time is 11.53145694732666
            # p=Thread(target=work)  #run time is 2.06762957572937
            l.append(p)
            p.start()
        for p in l:
            p.join()
        stop=time.time()
        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()
    #     temp=n
    #     time.sleep(0.1)
    #     n=temp-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)
    #     # pass
    '''
    对于不同的数据,要想保证安全,必须加不同的锁处理
    
    GIL并不能保证数据的安全,它是对Cpython解释器加锁,针对的是线程
    
    保证的是同一个进程下多个线程之间的安全
    
    '''
    from threading import Thread,Lock
    
    import time
    
    mutex=Lock()
    n=100
    
    def task():
        global n
        mutex.acquire()
        temp=n
        time.sleep(0.1)  #模拟网络延迟
    
        n=temp-1
        mutex.release()
    
    l_list=[]
    for i in range(100):
        t=Thread(target=task)
        t.start()
        l_list.append(t)
    
    for t in l_list:
        t.join()
    
    print(n)  #0

    死锁和递归锁

    #死锁
    '''
    import time
    from threading import Thread,Lock
    
    mutexA=Lock()
    mutexB=Lock()
    
    class MyThead(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)
            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)
    
    
    if __name__ == '__main__':
        for i in range(10):
            t=MyThead()
            t.start()
    
    '''
    #递归锁(解决产生死锁现象)  引用计数0  同一个人(每引用一次,计数+1),下面的人必须等到第一个人释放锁才可以抢
    # from threading import Thread,RLock
    
    # mutesA=mutexB=RLock()  #抢锁之后会有一个计数,抢一次计数加1
    import time
    from threading import Thread,RLock
    
    mutexA=mutexB=RLock()
    
    
    class MyThead(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)
            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)
    
    
    if __name__ == '__main__':
        for i in range(10):
            t=MyThead()
            t.start()
    
    
    '''
    自定义锁:一次acquire对应一次release,
    递归锁:一次acquire可以不一定要对应release,每产生一次acquire,第一个抢到锁的人的引用计数就+1,除非第一个人释放,否则别人就不会抢到锁
    递归锁是解决自定义锁出现的死锁现象
    '''

    信号量

    #钥匙串  公共厕所
    
    from threading import Thread,Semaphore
    import time,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()

    event事件

    from threading import Event,Thread
    
    import time
    
    event=Event()
    
    
    def light():
        print('红灯亮着!')
        time.sleep(3)
        event.set()  #解除阻塞,给我的event发了一个信号
        print('绿灯亮着')
    
    
    def car(i):
        print('%s 正在等红灯了'%i)
        event.wait()  #阻塞
        print('%s 加油飙车'%i)
    
    t1=Thread(target=light)
    t1.start()
    
    for i in range(10):
        t=Thread(target=car,args=(i,))
        t.start()

    线程queue

    import queue
    
    #普通q
    # q=queue.Queue(3)
    # q.put(1)
    # q.put(2)
    # q.put(3)
    # print(q.get())
    # 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((1,'c'))
    q.put((1,'a'))
    q.put((4,'a'))
    print(q.get())
  • 相关阅读:
    微信小程序--数据存储
    微信小程序---setData
    关于MVC中 服务器无法在发送 HTTP 标头之后修改 cookie此类问题的解决
    获取Web项目中的控制器类以及类中Action方法
    使用Attribute限制Action只接受Ajax请求
    Dapper 返回Sql server 自增长ID 标识列SCOPE_IDENTITY
    根据数据库反向生成PD
    Git常用命令大全,迅速提升你的Git水平
    官方VisualStudio.gitignore配置
    Win10-1909删除自带的微软输入法,添加美式键盘
  • 原文地址:https://www.cnblogs.com/mcc61/p/10836052.html
Copyright © 2020-2023  润新知