用Python中的Coroutines实现“SystemCalls”

时间:2015-01-02 07:44:31

标签: python coroutine

我目前正在阅读教程文档http://www.dabeaz.com/coroutines/Coroutines.pdf,并陷入(纯协程)多任务部分,特别是系统调用部分。

令我困惑的部分是

class Task(object):
    taskid = 0
    def __init__(self,target):
        Task.taskid += 1
        self.tid = Task.taskid # Task ID
        self.target = target # Target coroutine
        self.sendval = None # Value to send

    def run(self):
        return self.target.send(self.sendval)


def foo():
    mytid = yield GetTid()
    for i in xrange(5):
        print "I'm foo", mytid
        yield


class SystemCall(object):
    def handle(self):
        pass

class Scheduler(object):
    def __init__(self):
        self.ready = Queue()
        self.taskmap = {}

    def new(self, target):
        newtask = Task(target)
        self.taskmap[newtask.tid] = newtask
        self.schedule(newtask)
        return newtask.tid

    def schedule(self, task):
        self.ready.put(task)

    def mainloop(self):
        while self.taskmap:
        task = self.ready.get()
        try:
            result = task.run()
            if isinstance(result,SystemCall):
                result.task = task
                result.sched = self
                result.handle()
                continue
            except StopIteration:
                self.exit(task)
                continue
        self.schedule(task)

实际呼叫

sched = Scheduler()
sched.new(foo())
sched.mainloop()

我不明白的部分是如何将tid分配给foo()中的mytid?按照事物的顺序,它似乎是(从sched.mainloop()开始)。如果流量错误,请纠正我。

假设:让我们说出一些事情

the_coroutine = foo()
scheduler = Scheduler
the_task = scheduler.new(the_coroutine) # assume .new() returns the task instead of tid
  1. 调度程序: .mainloop()被称为
  2. 调度程序: the_task.run()被称为
  3. the_task: the_coroutine.send(无)被称为
  4. the_corou:yield GetTid(),它将一个GetTid实例返回给调度程序,然后将3中的None发送到循环中的yield语句。 (我是对的吗?)
  5. the_corou :(也在同一时间?)myTid被指定为GetTid()的实例?
  6. scheduler: result = theTask.run() the_task.run()< GetTid的实例>
  7. scheduler:result确实是SystemCall的一个实例
  8. 调度程序: result.handle()被称为
  9. GetTid实例: scheduler.schedule(the_task)
  10. 调度程序:当前迭代完成,启动一个新的
  11. scheduler :(假设队列中没有其他任务) the_task.run()被调用
  12. 调度程序: the_coroutine.send()被称为
  13. 我迷路了?
  14. 当它到达步骤12时,显然循环已经启动,并且只要调度程序运行相应的任务就能够打印tid。但是,当 foo()中的 mytid 的tid值完全正确时?我确信我在流程中遗漏了一些东西,但在哪里(甚至完全错误)?

    然后我注意到Task对象调用 .send()的部分,它返回一个值,所以 .send()会返回一个值吗?

1 个答案:

答案 0 :(得分:1)

您似乎省略了调度程序的new方法,这几乎肯定是分配发生的地方。我想,得到的GetTid()的结果会立即使用.send()发送回协程。

关于.send(),是的,你正确,.send()返回一个值。

请尝试以下示例查看正在进行的操作。 .send为= yield左侧的变量赋值,并在协程内执行代码,直到它到达下一个yield。在这一点上,协程产生,无论它产生什么,都是.send的返回值。

>>> def C():
...     x = yield
...     yield x**2
...     print 'no more yields left'
...
>>> cor = C()
>>> cor.next()
>>> yielded = cor.send(10)
>>> print yielded
100
>>> cor.next()
no more yields left
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

将一些评论中的内容转移到答案中

那么,x = yield y如何运作?

当协同程序命中该行代码时,它yields的值为y,然后暂停执行,等待某人用参数调用其.send()方法。

当有人调用.send()时,.send中的参数被分配给变量x,并且协同程序从那里开始执行代码直到其下一个yield class GetTid(SystemCall): def handle(self): self.task.sendval = self.task.tid self.sched.schedule(self.task) 1}}陈述。

编辑:哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇.. 通过链接材料,看起来GetTid的这个定义就是我们所追求的。

if isinstance(result,SystemCall):
    result.task = task
    result.sched = self
    result.handle() # <- This bit!
    continue

我引用他的演讲:&#34;这个操作很微妙&#34;。哈哈。

现在看一下主循环:

result

GetTid这里是handle对象,它运行task方法设置其对象。 sendval tid属性任务的task.run(),并通过将任务放回队列来安排任务。

从队列中检索任务后,再次运行class Task(object): ... def run(self): return self.target.send(self.sendval) 方法。让我们看看Task对象定义:

task.run()

第二次调用sendval时,它会将result.handle()值(之前由tid设置为.target)发送到foo } { - {1}}协程。这是foo协程对象最终接收其mytid的值的位置。

foo coroutine对象一直运行到下一个yield,沿途打印其消息,然后返回None(因为{{1}右边没有任何内容}})。 yieldNone方法的返回值。

这不是task.run()的实例,因此在第二次传递时不会处理/安排任务。

其他邪恶的事情也可能发生,但那是我现在所看到的流量。