Python多线程—定时器
在实际应用中,我们经常需要使用定时器去触发一些事件。Python中通过线程实现定时器timer,其使用非常简单。
在使用Python定时器时需要注意如下4个方面:
- 定时器构造函数主要有2个参数,第一个参数为时间,第二个参数为函数名,第一个参数表示多长 时间后调用后面第二个参数指明的函数。第二个参数注意是函数对象,进行参数传递,用函数名(如fun_timer)表示该对象,不能写成函数 执行 语句fun_timer(),不然会报错。用type查看下,可以看出两者的区别。
- 必须在定时器执行函数内部重复构造定时器,因为定时器构造后只执行1次,必须循环调用。
- 定时器间隔单位是秒,可以是浮点数,如5.5,0.02等,在执 行函数fun_timer内部和外部中给的值可以不同。如上例中第一次执行fun_timer是1秒后,后面的都是5.5秒后执行。
- 可以使用cancel停止定时器的工作。
案例
"""
使用定时器实现当前时间每秒循环输出一次
"""
import datetime
from threading import Timer
# 定时器
class Clock(object):
# 初始化
def __init__(self):
self.__timer = Timer(1, self.__run)
self.__timer.start()
# 定时器循环
def __run(self):
# 打印当前时间
time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(time)
# 重新设置定时器
self.__timer = Timer(1, self.__run)
# 启动定时器
self.__timer.start()
if __name__ == '__main__':
# 创建定时器
clock = Clock()
队列
Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。可以使用队列来实现线程间的同步。
常用方法:
Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False,Queue.full 与 maxsize 大小对应
Queue.get([block[, timeout]])获取队列,timeout等待时间
Queue.get_nowait() 相当于Queue.get(False),非阻塞方法
Queue.put(item) 写入队列,timeout等待时间
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号。每个get()调用得到一个任务,接下来task_done()调用告诉队列该任务已经处理完毕。
Queue.join() 实际上意味着等到队列为空,再执行别的操作
示例:
from Queue import Queue,LifoQueue,PriorityQueue
#先进先出队列
q=Queue(maxsize=5)
#后进先出队列
lq=LifoQueue(maxsize=6)
#优先级队列
pq=PriorityQueue(maxsize=5)
for i in range(5):
q.put(i)
lq.put(i)
pq.put(i)
print "先进先出队列:%s;是否为空:%s;多大,%s;是否满,%s" %(q.queue,q.empty(),q.qsize(),q.full())
print "后进先出队列:%s;是否为空:%s;多大,%s;是否满,%s" %(lq.queue,lq.empty(),lq.qsize(),lq.full())
print "优先级队列:%s;是否为空:%s,多大,%s;是否满,%s" %(pq.queue,pq.empty(),pq.qsize(),pq.full())
print q.get(),lq.get(),pq.get()
print "先进先出队列:%s;是否为空:%s;多大,%s;是否满,%s" %(q.queue,q.empty(),q.qsize(),q.full())
print "后进先出队列:%s;是否为空:%s;多大,%s;是否满,%s" %(lq.queue,lq.empty(),lq.qsize(),lq.full())
print "优先级队列:%s;是否为空:%s,多大,%s;是否满,%s" %(pq.queue,pq.empty(),pq.qsize(),pq.full())
线程池
使用线程池可以有效地控制系统中并发线程的数量。当系统中包含有大量的并发线程时,会导致系统性能急剧下降,甚至导致 Python 解释器崩溃,而线程池的最大线程数参数可以控制系统中并发线程的数量不超过此数。
使用线程池来执行线程任务的步骤如下:
1.调用 ThreadPoolExecutor 类的构造器创建一个线程池。
2.定义一个普通函数作为线程任务。
3.调用 ThreadPoolExecutor 对象的 submit() 方法来提交线程任务。
4.当不想提交任何任务时,调用 ThreadPoolExecutor 对象的 shutdown() 方法来关闭线程池。
主线程
: 相当于生产者,只管向线程池提交任务。并不关心线程池是如何执行任务的。因此,并不关心是哪一个线程执行的这个任务。
线程池
: 相当于消费者,负责接收任务,并将任务分配到一个空闲的线程中去执行。