Python 多线程编程2

2020-03-22  本文已影响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
上一篇下一篇

猜你喜欢

热点阅读