• 多线程并发--竞争问题


    前言:GIL

    GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。GIL只在cpython中才有,因为cpython调用的是c语言的原生线程,所以他不能直接操作cpu,只能利用GIL保证同一时间只能有一个线程拿到数据。而在pypy和jpython中是没有GIL的。

    在python中多线程的并发只能每一刻执行一个线程,那么就会产生一个竞争资源问题,线程是共享数据的。

    在这用力扣的题目解释用同步锁机制解决竞争条件

    假设有一个方法 withdraw(amount),如果请求量小于当前余额,则从当前余额中减去请求量,然后返回余额。方法定义如下:

    1 balance = 500
    2 def withdraw(amount):
    3     if (amount < balance):
    4         balance -= amount
    5     return balance

    正常结果余额不能为负。但此时我用两个线程不同参数执行该方法时,如:线程1 withdraw(400)和线程2 withdraw(200)的执行流程如下图:

     对于这种问题,我们可以利用锁来解决,将一个线程的关键执行部分加上锁,执行完在释放。如下图

     在3、4步的时候,线程2执行到来关键部分所以加上来锁,因此线程1此时处于休眠状态,5、6步的时候同理。

    例题:--同步锁

    三个不同的线程将会共用一个 Foo 实例。

    线程 A 将会调用 one() 方法
    线程 B 将会调用 two() 方法
    线程 C 将会调用 three() 方法
    请设计修改程序,以确保 two() 方法在 one() 方法之后被执行,three() 方法在 two() 方法之后被执行。

    思路:利用依赖关系,创建一个变量firstJobDone协调one()和two()之间的执行顺序,在创建一个变量secondJobDone协调two()和three()之间的执行关系

    • 首先初始化共享变量 firstJobDone 和 secondJobDone,初始值表示所有方法未执行。
    • 方法 first() 没有依赖关系,可以直接执行。在方法最后更新变量 firstJobDone 表示该方法执行完成。
    • 方法 second() 中,检查 firstJobDone 的状态。如果未更新则进入等待状态,否则执行方法 second()。在方法末尾,更新变量 secondJobDone 表示方法 second() 执行完成。
    • 方法 third() 中,检查 secondJobDone 的状态。与方法 second() 类似,执行 third() 之前,需要先等待 secondJobDone 的状态。
    from threading import Lock
    
    class Foo:
        def __init__(self):
            self.firstjobDone = Lock()
            self.secondjobDone = Lock()
            self.firstjobDone.acquire()   # 请求加锁
            self.secondjobDone.acquire()
    
    
        def first(self, printFirst: 'Callable[[], None]') -> None:
            
            # printFirst() outputs "first". Do not change or remove this line.
            printFirst()
            self.firstjobDone.release()   # 释放锁
    
    
        def second(self, printSecond: 'Callable[[], None]') -> None:
            
            # printSecond() outputs "second". Do not change or remove this line.
            with self.firstjobDone:    # 上下文管理器,可获取和释放锁
                printSecond()
                self.secondjobDone.release()
    
    
        def third(self, printThird: 'Callable[[], None]') -> None:
            
            # printThird() outputs "third". Do not change or remove this line.
            with self.secondjobDone:
                printThird()

    题目出处:https://leetcode-cn.com/problems/print-in-order/

  • 相关阅读:
    13、java中8中基本类型
    12、static final
    11、final详解
    10、java初始化顺序
    9、java中static详解
    9、接口和抽象类
    8、java内部类
    7、手工编译和运行时注意事项
    推荐10 款 SVG 动画的 JavaScript 库
    让优秀的文章脱颖而出---极客头条使用体验
  • 原文地址:https://www.cnblogs.com/leisunny/p/13469657.html
Copyright © 2020-2023  润新知