提起任务队列,Java中的concurrent应该是这方面的杰出代表,可以参考我以前写的Blog。我这里想说的是用Python实现的任务队列。
在Python的标准库中没有任务队列,不过可以参考Java的实现,自己做一个任务队列。任务队列主要由三个方面组成:
1) 优先队列(PriorityQueue),用于将最近需要执行的任务放到前面。一般使用Heap,也可以参考我写的Blog。
2) 阻塞队列,在Java的实现中,是以内嵌一个优先队列实现的。不过在我的Python实现中,是直接从优先队列继承而来。主要关注点是取出一个任务(优先队列的最优解)时,如果时间未到,必须要睡眠等待。
3) 延迟任务,任务的执行体。提供了prerun(),run()和postrun()方法。继承类需要实现run()
关于延迟任务,主要有以下属性:
1) 下次执行的时间。当下次执行的时间小于或者等于当前时间时,就要执行了。反之,则等待。
2) 两次任务执行的间隔时间。
3) 任务运行模式。
关于任务运行模式有以下三种情况:
1) 周期性。即每隔一段时间执行该任务。比如每10分钟执行一次任务。
2) 间隔性。即第一次任务执行完成后,隔一段时间再执行该任务,比如每任务间隔10分钟执行。
3) 一次性。即该任务只执行一次。
如果实现了以上的一些特性,一个任务队列就实现了。
不过有一个很实际的问题:如何退出任务队列,即使当前有任务还没有运行?这里使用了一个技巧:向任务队列里投放一个ExitTask的任务队列,该任务的执行时间就是当前时间,所以它会马上执行,当线程发现是ExitTask时,就退出线程。
另外以前是把代码保存到本机上,在换电脑或者搬迁后这些代码就不见影踪了。现在就把代码放到了Google Code上去。申请还是很方便的,我就为这个简单的代码申请了一个pytask.
下面是一个测试代码:
from threading import Thread
from pytask.task import *
from time import sleep, time
class MyTask(DelayedTask):
def run(self):
print 'Execute the task…'
sleep(3)
class Test(Thread):
def __init__(self, dq, name='Test'):
Thread.__init__(self)
self.dq = dq;
self.setName(name)
def run(self):
while True:
task = self.dq.take()
if task.isExit():
print 'Thread is going to shutdown now.'
# put the logo back to queue so other theads can exit
pq.put(task)
break
task.preRun(self.dq)
print self.getName() + ' ' + str(task)
task.run()
task.postRun(self.dq)
class Add(Thread):
def __init__(self, dq, name='Test'):
Thread.__init__(self)
self.dq = dq;
self.setName(name)
def run(self):
for index in range(size):
import random
r = random.randint(5, size)
sleep(1)
task = MyTask(time() + r, r, 'Task' + str(index))
print task
pq.put(task)
sleep(100)
# after 100s exit
pq.put(ExitTask)
if __name__ == '__main__':
d = []
# 200 tasks
size = 200
# 延迟队列
pq = DQueue()
# 5个执行线程
take = Test(pq, 't1-')
take.start()
take = Test(pq, 't2-')
take.start()
take = Test(pq, 't3-')
take.start()
take = Test(pq, 't4-')
take.start()
take = Test(pq, 't5-')
take.start()
# 添加任务
add = Add(pq, 'A--')
add.start()