Event
记得之前说过线程可以对同一进程下的其他线程进行一定程度上的控制,而这里的Event就实现了这一点
Event就相当于一个全局的标志变量,提供了一些方法,可以在各个线程中修改这个标志变量而不需要声明全局变量,先看看Event的几个常用方法
event = threading.Event() # 生成Event实例
event.set() # 设置存在,即相当于设置为True
event.clear() # 设置清空,即相当于设置为false
event.is_set() # 检测是否存在,存在返回True
event.wait() # 检测是否设置存在,如果未设置,则程序一直阻塞
然后我们通过一个简单的红绿灯小程序来看一下如何使用Event
import threading
import time
# 生成Event实例
event = threading.Event()
# 先写红绿灯方法
def light():
# 进入循环红绿灯一直规律切换
while True:
# 设置存在,进入绿灯状态
event.set()
# 打印绿灯行
print('\033[42;1m green light and go!\033[0m')
# 设置时间间隔5秒
time.sleep(5)
# 清空设置,进入红灯状态
event.clear()
# 打印红灯停
print('\033[41;1m red light and stop!\033[0m')
# 红灯间隔5秒
time.sleep(5)
# 定义汽车车方法
def car(name):
# 这里进入循环因为需要一直不停检测设置的Event实例
while True:
# 判断是否设置,如果设置则为绿灯则车辆行驶
if event.is_set():
# print(event.is_set())
print('%s is running' % name)
time.sleep(1)
else:
# 否则则为红灯进入等待状态,使用event.wait()阻塞程序检测是否进入绿灯状态
print('%s is waiting the green light on ...' % name)
event.wait()
print('turn on!')
if __name__ == '__main__':
l = threading.Thread(target=light)
car1 = threading.Thread(target=car, args=('长安奔奔',))
car2 = threading.Thread(target=car, args=('甲壳虫',))
l.start()
car1.start()
car2.start()
Event的用法比较简单,这里稍微注意一下两个while就行了
队列queue
怎么理解队列呢?队列就好比一个容器,一个存放数据或者其他东西的容器,有人可能会问那直接用列表不就好了,确实队列跟列表有很多的相似之处,都有顺序性,但是队列拿出一个数据之后这个数据就没有了,而列表所谓的拿出数据只是copy了一份数据,也就是说列表是单纯的存储了数据,而队列就好像真实存在的一个排好队的队伍,至于其他的优点,在你使用了之后会有更深的了解
import queue
q = queue.Queue(maxsize=0) # 生成先入先出队列实例,有一个参数maxsize设置队列大小,默认是没有大小的,可以一直放数据
q = queue.LifoQueue(maxsize=0) # last in first out:生成后入先出队列实例,比如货架上的东西后来放上去的在最外面会被人先拿走
q = queue.PriorityQueue(maxsize=0) # 优先级队列,可以设置优先级来实现排序,这里存入的为元组类型:优先级(数字,小的数字优先级高)对应放入的东西
q.put() # 放入元素,还有block参数和timeout参数,block参数设置是否阻塞,默认为True,就是说当一个队列最大元素个数为20的话如果你放入第21个则程序会阻塞,timeout设置阻塞时间
q.get() # 取出元素,跟put有同样的参数,不过是如果取出的队列里面没有元素了才会触发,然后进入等待有人往队列里面放元素
q.put_nowait() # 无阻塞直接抛出异常等价q.put(block=False)
q.get_nowait() # 无阻塞直接抛出异常等价q.get(block=False)
q.qsize() # 返回队列q当前元素个数,这里注意不是队列q的最大元素个数
下面来看看如何使用
先入先出
后入先出
优先级队列
设置大小1放入两个之后阻塞
设置不阻塞直接抛出错误Full
get方法的阻塞与不阻塞设置方法与上面类似
也可以使用get_nowait/put_nowait方法设置不阻塞,这里队列为空了,再取出直接抛出Empty错误
接下来我们就用队列和多线程实现我们以后也会经常用到的生产者消费者模型:
首先理解一下生产者消费者模型:
在这个模型中,我理解划分为三个部分,生产者、消费者和中介容器,生产者和消费者不直接通信,而是通过阻塞队列通信,也就是这个容器,生产者只在容器未满时生产,容器满的时候阻塞生产者的生产;消费者只在容器不为空的时候消费,容器空了之后阻塞消费者消费;这个容器的作用就是平衡协调生产和消费的关系
import threading
import queue
import time
# 生成队列容器
q = queue.Queue()
# 生产者
def producer():
# 计数方式防止生产过多
count = 1
# 进入生产循环
while True:
# 判断队列中商品个数是否小于10,小于10则生产,否则阻塞
if q.qsize() < 10:
q.put('商品%s' % count)
count += 1
# 消费者
def consumers(name):
# 每隔一秒拿出一个商品
while q.qsize() > 0:
print('[%s] bought the [%s]' % (name, q.get()), q.qsize())
time.sleep(1)
# 启动两个消费者线程一个生产者线程
man1 = threading.Thread(target=consumers, args=('test1', ))
man2 = threading.Thread(target=consumers, args=('test2', ))
goods = threading.Thread(target=producer)
goods.start()
man1.start()
man2.start()
上面是一个非常简单的生产者消费者模型,可以看到商品个数一直为9个,其实一直是10个,因为生产者生产的非常快,而消费者每一秒才买一个商品,然后生产者会立即填充,当然这种关系可以自己来调节
转载请注明出处
python自学技术互助扣扣群:670402334