美文网首页
Python 多线程编程2

Python 多线程编程2

作者: 一个扫地的垃圾 | 来源:发表于2020-03-22 14:32 被阅读0次

    1 守护线程

    守护线程(Daemon thread),又叫做后台线程。此类线程的特点是当其他线程都执行结束时,无论守护线程是否完成,都直接结束当前工作。例如,python中的垃圾回收机制就是守护线程的代表,当主线程和其他线程完成工作后,垃圾回收机制也就没有再继续执行的必要了。

    创建守护线程可以在创建线程时,将daemon属性值设置为True,下面的例子展示了如何创建守护线程。

    # coding:utf-8
    import threading
    def action(length):
        for i in range(length):
            print(threading.current_thread())
    if __name__ == "__main__":
        t = threading.Thread(target=action, args=(20,), daemon=True)
        # t.daemon = True  # 此中方法也可以开启守护线程
        t.start()
        for i in range(5):
            print(threading.current_thread())
    

    输出结果:

    <Thread(Thread-1, started daemon 123145454514176)>
    <Thread(Thread-1, started daemon 123145454514176)>
    <Thread(Thread-1, started daemon 123145454514176)>
    <Thread(Thread-1, started daemon 123145454514176)>
    <Thread(Thread-1, started daemon 123145454514176)>
    <Thread(Thread-1, started daemon 123145454514176)>
    <Thread(Thread-1, started daemon 123145454514176)>
    <Thread(Thread-1, started daemon 123145454514176)>
    <Thread(Thread-1, started daemon 123145454514176)>
    <_MainThread(MainThread, started 4672699840)><Thread(Thread-1, started daemon 123145454514176)>
    <_MainThread(MainThread, started 4672699840)>
    <_MainThread(MainThread, started 4672699840)>
    <_MainThread(MainThread, started 4672699840)>
    <_MainThread(MainThread, started 4672699840)>
    

    2 互斥锁

    互斥锁用于解决线程之间数据不同步的问题,例如给出下面一段代码,用于模仿银行用户取钱的操作:

    # coding:utf-8
    import threading
    import time
    
    
    class Account(object):
        """
        定义账户的类
        """
        def __init__(self, account_no, balance):
            """
            :param account_no: 唯一的账户号
            :param balance: 账户对应的余额
            """
            self.account_no = account_no
            self.balance = balance
    
    
    def withdraw(account, draw_amount):
        """
        取钱操作
        :param account: 账户类的实例化对象
        :param draw_amount: 取钱金额
        :return: None
        """
        if account.balance >= draw_amount:
            print(threading.current_thread().getName() + " Withdraw success ", draw_amount)
            time.sleep(0.5)  # sleep函数会使当前线程阻塞,从而切换到另一线程
            account.balance -= draw_amount
            print("balance is ", account.balance)
        else:
            print("Withdraw failure")
    
    
    if __name__ == "__main__":
        # 创建一个账户,两个用户分别取钱,会出现数据不同步引发的错误
        acc = Account("62102034", 1000)  # 创建账户,包含两个属性,账户号和余额
        th1 = threading.Thread(target=withdraw, args=(acc, 800))
        th2 = threading.Thread(target=withdraw, args=(acc, 800))
        th1.start()
        th2.start()
    

    输出结果:

    Thread-1 Withdraw success  800
    Thread-2 Withdraw success  800
    balance is  200
    balance is  -600
    

    此时会出现一个问题,当第一个线程执行余额和取钱数目判断操作时,系统判定可以成功取钱,但是紧接着执行了一个sleep的函数使得当前线程进入阻塞状态,第二个线程重复上述操作,最后造成了两个线程同时可以成功取钱。threading模块引入RLock类可以锁定当前进程,从而可以实现在一个线程上实现独享数据。

    lock = threading.RLock()类构建一个互斥锁的对象,用于锁定当前进程的数据
    lock.acquire() 对lock对象加锁
    lock.release() 对lock对象释放锁
    acquire和release方法必须成对出现
    

    RLock对象的acquirerelease方法必须成对出现,同时将两个方法应用到线程执行的函数体中,就可以实现对线程加锁。

    # coding:utf-8
    import threading
    import time
    
    
    class Account(object):
        # 定义账户的类
        def __init__(self, account_no, balance):
            """定义构造器"""
            self.account_no = account_no
            self._balance = balance  # 为了账户安全,定义余额为类的内部属性,
            self.lock = threading.RLock()  # 定义lock属性为互斥锁对象
    
        def withdraw(self, withdraw_amount):
            """
            取钱操作
            :param withdraw_amount: 取钱金额
            :return: None
            """
            self.lock.acquire()  # 线程加锁
            if self._balance >= withdraw_amount:
                print(threading.current_thread().getName(), " Withdraw success ", withdraw_amount)
                time.sleep(0.5)
                self._balance -= withdraw_amount  # 更新余额
                print("balance is ", self._balance)
            else:
                print(threading.current_thread().getName(), "Withdraw failure")
            self.lock.release()  # 线程释放锁
    
    
    if __name__ == "__main__":
        acc = Account("62102034", 1000)
        th1 = threading.Thread(target=acc.withdraw, args=(800,))
        th2 = threading.Thread(target=acc.withdraw, args=(800,))
        th1.start()
        th2.start()
    

    输出结果:

    Thread-1  Withdraw success  800
    balance is  200
    Thread-2 Withdraw failure
    

    另外,也可以使用上一小节提到的join方法应用到某一个线程,使其优先占用CPU资源完成当前线程工作。

    # coding:utf-8
    import threading
    import time
    
    
    class Account(object):
        # 定义账户的类
        def __init__(self, account_no, balance):
            """定义构造器"""
            self.account_no = account_no
            self._balance = balance  # 为了账户安全,定义余额为类的内部属性,
            self.lock = threading.RLock()  # 定义lock属性为互斥锁对象
    
        def withdraw(self, withdraw_amount):
            """
            取钱操作
            :param withdraw_amount: 取钱金额
            :return: None
            """
            # self.lock.acquire()  # 线程加锁
            if self._balance >= withdraw_amount:
                print(threading.current_thread().getName(), " Withdraw success ", withdraw_amount)
                time.sleep(0.5)
                self._balance -= withdraw_amount  # 更新余额
                print("balance is ", self._balance)
            else:
                print(threading.current_thread().getName(), "Withdraw failure")
            # self.lock.release()  # 线程释放锁
    
    
    if __name__ == "__main__":
        acc = Account("62102034", 1000)
        th1 = threading.Thread(target=acc.withdraw, args=(800,))
        th2 = threading.Thread(target=acc.withdraw, args=(800,))
        th1.start()
        th1.join()
        th2.start()
    

    输出结果:

    Thread-1  Withdraw success  800
    balance is  200
    Thread-2 Withdraw failure
    

    相关文章

      网友评论

          本文标题:Python 多线程编程2

          本文链接:https://www.haomeiwen.com/subject/kixvyhtx.html