位于/pox/lib/recoco中的recoco.py在Pox中起到是任务队列的作用. 也就是说, 除了常规的监听交换机送上来的事件这个任务外, Pox还提供了方法给用户添加自己的任务进Pox中. 对于什么时候需要添加自己的任务, 我还没得到一个合理准确的答案. 目前我觉得, 我们的"任务"需要和监听交换机事件同等级. 在recoco/example.py中, 开发者给出的例子是收集与交换机连接的socket并对socket进行处理. 本文将分为两个部分. 第一个部分讲解如何将自己的任务添加入任务队列中, 第二个说明Pox实现该功能的方法.
一. 添加我们自己的任务
首先, Pox中的任务都有个基类, 叫做Task, 位于pox/lib/recoco, 所以我们需要用from pox.lib.recoco import *把它和它需要的东西导入进我们的模块中.
其次, 让我们作为任务的类继承Task类, 这里就不在赘述.
再次, 我们的类需要定义一个run函数, 参数为空.
最后, 在run函数内放入下列代码
while core.running:
rlist,wlist,elist = yield Select(self.sockets, [], [], 3)
#Our code
如果你知道yield和Select()的作用, 那行代码可自行替换成自己的.
搞定!
二. Pox实现该任务功能的方法
recoco.py中主要通过两个大类来实现任务队列, Scheduler和Task, 其中Task是继承BaseTask类.
- Scheduler类的功能是实现队列. 该类中保存了任务的列表, 并用线程的方法不停读取队列和运行任务.
- Task类之前已经见过了, 是实现任务的类.
任务队列的执行过程及其重要函数如下. 简单的说就是每次从Scheduler的任务列表中读取第一个任务并执行, 执行完毕后将该任务放入队列末尾.
执行过程:
Scheduler.__init__(): 建队列_ready, 建进程事件_event. 执行self.runThreaded(daemon)建线程
scheduler.runThreaded(): 执行Thread(target = self.run)设置线程入口(run)
scheduler.run(): 是个循环, 每次循环 执行self.cycle()处理一个task
scheduler.cycle(): 执行队列里第一个任务的basetask.execute() 来处理task
basetask.execute(): 执行basetask.run的下一个yield.用的是yield的send方法
而一个Task类又是通过下列过程将自己加入到任务列表中的.
Basetask.__init__: 获得任务id, 执行run.
Basetask.start: 执行scheduler.schedule()/fastschedule()
scheduler.schedule()/fastschedule(): 将task加入队列
至此, 主要的东西都已经讲完了. 但是recoco不仅仅提供这些基本的任务队列功能, 所以下面是我发现的几个Tips.
BlockingOperation:
一个可以被视为对任务进行系统调用的基类
初始化函数不能让任务在没有yield的情况下意外地启动一个系统调用
Scheduler中的初始化有一句:
self._selectHub = SelectHub(self, useEpoll=useEpoll)
而SelectHub会启动一个线程,入口函数是_threadProc
Timer:
继承task.
功能是N秒后执行一次callback函数
一个Task类, 初始化时除了初始化task类,
还判断传入的”start”参数是否为true(默认为true), true的话就自动执行task.start把该timer任务加入线程中
Task返回值:
让task的run返回一个数字和返回一个sleep(blockoperation)的系统调用的作用是基本一样的, 都是N秒后再唤醒该任务, 不过sleep更灵活, 可以是相对时间也可以是绝对时间.