我目前正在阅读教程文档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
当它到达步骤12时,显然循环已经启动,并且只要调度程序运行相应的任务就能够打印tid。但是,当 foo()中的 mytid 的tid值完全正确时?我确信我在流程中遗漏了一些东西,但在哪里(甚至完全错误)?
然后我注意到Task对象调用 .send()的部分,它返回一个值,所以 .send()会返回一个值吗?
答案 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}右边没有任何内容}})。 yield
是None
方法的返回值。
这不是task.run()
的实例,因此在第二次传递时不会处理/安排任务。
其他邪恶的事情也可能发生,但那是我现在所看到的流量。