zoukankan      html  css  js  c++  java
  • GIL锁、死锁、递归锁、定时器

    GIL (Global Interpreter Lock) 锁

    '''
    定义:
    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并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成

    可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的

    JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。所以这

    里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL

    垃圾回收机制

    x = 10
    x = 2               # x重新赋值为2 , Cpython 解释器会开启一个垃圾回收线程,把 10 给回收掉
    y = 10              #如果多线程并发或并行,就有可能其他线程会要用到这个地址,一个要回收,一个要用,就会产生矛盾.这显然是不行的

    有了GIL后:

    垃圾回收线程执行的时候,其他线程不能动(垃圾回收线程从头到尾执行完毕,其他线程才能运行)

    其他线程执行的时候,垃圾回收线程不能动

    垃圾回收:定义一个变量,当这个变量以后不再被引用,这个变量就要回收掉,解释器开了线程帮程序员干了这活(其他语言需要程序员自己回收),把程序员解放出来了.

    python的多线程特点:

      基于cpython写的,同一时刻只能有一个线程执行

      cpu是干计算的,不是io ,所以io密集型的程序用不了多核也影响不大,基本忽略不计

    ==================================

    多个进程,每个进程只有一个线程,有没有gil无所谓(gil锁作用与多线程)

    所以,多个进程可以用多核(Cpython)

    GIl本质是互斥锁

    既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。

    可以肯定的一点是:保护不同的数据的安全,就应该加不同的锁。

    GIL 和 Lock

    GIL锁,保护的是解释器级别的数据

    Lock锁,保护的是用户自己的数据

    应用:

      多线程用于IO密集型,如socket,爬虫,web

      多进程用于计算密集型,如金融分析

    =========================

    3个线程都去抢GIL锁,假如线程1 抢到了,那么线程1 就会把代码传给解释器编译执行,然后拿到Lock,遇到sleep,睡0.1秒,操作系统强制线程1把GIL锁释放,线程1 睡的时候,线程1 就没

    资格抢gil,所以剩下的是线程2和线程3它们俩抢,当一个抢到GIL锁后,就会把代码传给解释器执行,当运行到Lock时,下面的代码已经被线程1锁住,然后系统就会强制这个线程释放GIL

    锁,.直到线程1 睡醒了 ,才有资格抢GIL,当线程1再次抢到GIL后,线程1就会从当前位置继续往下执行.

    小节:
      1.每一个Cpython进程内都有一个GIL
      2.GIL导致同一个进程内的多个线程同一时间只能有一个运行
      3.之所以有GIL,是因为Cpython的内存管理不是线程安全的
      4.对于计算密集型用多进程,IO密集型用多线程

    死锁和递归锁

    import time
    from threading import Thread, Lock
    
    
    class Myth(Thread):
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            mutexA.acquire()
            print('%s拿到A锁' % self.name)     #线程对象自带name属性
            time.sleep(0.2)
            mutexB.acquire()
            print('%s拿到B锁' % self.name)
            mutexB.release()
            print('%s释放B锁' % self.name)
            mutexA.release()
            print('%s释放A锁' % self.name)
    
        def f2(self):
            mutexB.acquire()
            print('%s拿到B锁' % self.name)
            time.sleep(0.2)
            mutexA.acquire()
            print('%s拿到A锁' % self.name)
            mutexA.release()
            print('%s释放A锁' % self.name)
            mutexB.release()
            print('%s释放B锁' % self.name)
    
    
    if __name__ == '__main__':
        mutexA = Lock()
        mutexB = Lock()
        for i in range(100):
            t = Myth()
            t.start()
    
    Thread-1拿到A锁
    Thread-1拿到B锁
    Thread-1释放B锁
    Thread-1释放A锁            释放掉之后再抢
    Thread-1拿到B锁
    Thread-2拿到A锁            一人拿一个,需要的都在对方手里,结果都拿不到对方的锁
    ..

    然后程序卡死了

    定时器

    定时器,指定n秒后执行某操作

    from threading import Timer
    
    
    def func(name):
        print('%s is done' % name)
    
    
    t = Timer(1, func, args=('kitty',))
    t.start()
    ##
    kitty is done  #一秒之后执行func
  • 相关阅读:
    用dos批处理程序检测是否安装.netframework,并自动安装后运行指定程序(.net自启动光盘的制做)
    生成pdf文件的好东西,itextsharp
    阳春三月来了
    新年快乐!
    无法启动 MS DTC 事务管理器。LogInit 返回错误 0x2. 怎么办?
    如何获取文件在系统中的图标?
    自定义工作流程的实现方案(初稿)
    [正能量系列]女性程序员篇
    [正能量系列]失业的程序员(一)
    我们在囧途之裁员篇
  • 原文地址:https://www.cnblogs.com/zhzhlong/p/9298872.html
Copyright © 2011-2022 走看看