欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python多线程-Event(事件对象)

程序员文章站 2022-03-07 16:57:37
Event 事件对象管理一个内部标志,通过 方法将其设置为 ,并使用 方法将其设置为 。`wait() True False`。 方法: is_set() 当且仅当内部标志为 时返回 。 set() 将内部标志设置为 。所有等待它成为 的线程都被唤醒。当标志保持在 的状态时,线程调用 是不会阻塞的。 ......

event

事件对象管理一个内部标志,通过set()方法将其设置为true,并使用clear()方法将其设置为falsewait()方法阻塞,直到标志为true。该标志初始为false

方法:
is_set()
当且仅当内部标志为true时返回true

set()
将内部标志设置为true。所有等待它成为true的线程都被唤醒。当标志保持在true的状态时,线程调用wait()是不会阻塞的。

clear()
将内部标志重置为false。随后,调用wait()的线程将阻塞,直到另一个线程调用set()将内部标志重新设置为true

wait(timeout=none)
阻塞直到内部标志为真。如果内部标志在wait()方法调用时为true,则立即返回。否则,则阻塞,直到另一个线程调用set()将标志设置为true,或发生超时。
该方法总是返回true,除非设置了timeout并发生超时。

生产者与消费之--event版

# -*- coding:utf-8 -*-
import threading
import time
import queue


event = threading.event()
goods = queue.queue(5)
num = 0


class producer(threading.thread):
    def run(self):
        global num
        while true:
            if goods.empty():
                event.clear()
                for _ in range(5):
                    goods.put('商品-' + str(num))
                    print('生产了商品-{0}.'.format(str(num)))
                    num += 1
                    time.sleep(1)
                event.set()


class customer(threading.thread):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.money = 7

    def run(self):
        while self.money:
            event.wait()
            self.money -= 1
            print('{0} 买了一个{1}.'.format(
                threading.current_thread().name, goods.get()))
            time.sleep(1)
        print('{0}没钱了,回家.'.format(threading.current_thread().name))


if __name__ == '__main__':
    p = producer(daemon=true)
    c1 = customer(name='alice')
    c2 = customer(name='bob')
    c2.start()
    p.start()
    c1.start()
    c1.join()
    c2.join()

运行结果:

生产了商品-0.
生产了商品-1.
生产了商品-2.
生产了商品-3.
生产了商品-4.
alice 买了一个商品-0.
bob 买了一个商品-1.
alice 买了一个商品-2.
bob 买了一个商品-3.
alice 买了一个商品-4.
生产了商品-5.
生产了商品-6.
生产了商品-7.
生产了商品-8.
生产了商品-9.
alice 买了一个商品-5.
bob 买了一个商品-6.
alice 买了一个商品-7.
bob 买了一个商品-8.
生产了商品-10.
alice 买了一个商品-9.
生产了商品-11.
生产了商品-12.
生产了商品-13.
生产了商品-14.
alice 买了一个商品-10.
bob 买了一个商品-11.
alice没钱了,回家.
bob 买了一个商品-12.
bob 买了一个商品-13.
bob没钱了,回家.

这里会出现一种特殊情况,当消费者线程较多时会大量出现:

生产了商品-0.
生产了商品-1.
生产了商品-2.
生产了商品-3.
生产了商品-4.
bob 买了一个商品-0.
alice 买了一个商品-1.
bob 买了一个商品-2.
alice 买了一个商品-3.
bob 买了一个商品-4.
生产了商品-5.                    # !!!!!
alice 买了一个商品-5.             # !!!!!
生产了商品-6.
生产了商品-7.
生产了商品-8.
生产了商品-9.
bob 买了一个商品-6.
alice 买了一个商品-7.
alice 买了一个商品-8.
bob 买了一个商品-9.
生产了商品-10.
生产了商品-11.
生产了商品-12.
生产了商品-13.
生产了商品-14.
alice 买了一个商品-10.
bob 买了一个商品-11.
bob 买了一个商品-12.
alice 买了一个商品-13.
bob没钱了,回家.
alice没钱了,回家.

这是因为生产者在轮询检查商品是否为空会有很小的延迟,在这个延迟中有消费者线程正好跑过了wait()方法,而阻塞在了商品获取这里(商品使用了队列,队列是线程安全的,当队列为空时,get()方法会阻塞),所以当生产者开始执行的时候,这个消费者因为商品队列里有数据就被立即唤醒了。