为什么协程不打印初始值无?

时间:2014-11-28 14:05:32

标签: python coroutine

这是follow-up co-routine question to another question。此代码段也摘自david beazley的示例代码(inline1.py)

为什么没有打印Got: None

class Task:

    def __init__(self, gen):
        self._gen = gen 

    def step(self, value=None):
        # Run to the next yield
        try:
            fut = self._gen.send(value)
            # Future returned
            fut.add_done_callback(self._wakeup)
        except StopIteration as exc:
            pass

    def _wakeup(self, fut):
        # Handler of results
        result = fut.result()
        #print(result)
        self.step(result) # Feedback loop(run to next yield)

if __name__ == '__main__':

    from concurrent.futures import ThreadPoolExecutor
    import time

    pool = ThreadPoolExecutor(max_workers=8)

    def func(x, y): 
        time.sleep(1)
        return x + y 

    def do_func(x, y): 
        result = yield pool.submit(func, x, y)
        print('Got:', result)

    t = Task(do_func(2,3))
    t.step()

1 个答案:

答案 0 :(得分:1)

经过一番挖掘后,我在这里发布了答案。

了解s.send(无)与s.next()

首先,我们需要了解s.send(None)s.next()

这是一个示例,表明s.send(None)

做同样的事情

s.next()将生成器推进到屈服声明。

摘自大卫的幻灯片:

def line_splitter(delimiter=None):
    print("Ready to Split")
    result = None
    while True:
        print("not yielded")
        line = (yield result)
        print("yielded.. [line = %s]" % line)
        result = line.split(delimiter)


if __name__ == "__main__":
    s = line_splitter(",")
    s.send(None)  # or use s.next()
    s.send("A,B,C")

Result:
>>> s = line_splitter(",")
>>> s.send(None)
Ready to Split
not yielded
>>> s.send('A,B,C')
yielded.. [line = A,B,C]
not yielded
['A', 'B', 'C']  # <-- Pause at line = (yield result)
                 # yield the result and wait for the next input from send()  


>>> s.send('E,F') # Now it receives the next input, so run to next (yield)
Yielded.. [line = E,F]
Not Yielded
['E', 'F']
>>>

现在,我们可以访问inline1.py来完成代码流程。

1)调用t.step()后,会fut = self._gen.send(None)运行None以提前

生成器在do_func()

中生成语句

fut = do_func(2,3).send(None)

def do_func(x, y): 
    result = yield pool.submit(func, x, y)
    print('Got:', result)

这里理解代码流的关键是generator.send(None)的功能。

发送(无)是推进发电机启动。这意味着,代码将暂停在

result = yield pool.submit(func, 2,3)但请将pool.submit(func,2,3)返回send()

与此同时,pool.submit(func, 2, 3)正在执行。

然后,它会在此处暂停,等待发送下一个值以填充结果

==&GT; result = (yield)(简体)或result = yield pool.submit(func,2,3)

但是,我们使用fut.add_done_callback(self._wakeup)来处理返回fut

pool.submit(func,2,3),其结果等于5

因此,当调用add_done_callback时,_wakeup()将检索结果

来自fut.result()的{​​{1}}是5。然后再次将5推入step()

2)然后,它来到下一个fut = self._gen.send(5)

现在,值5正被发送到结果。所以,result = 5

然后,它在这里打印出Got: 5

send()不再向fut提供数据,因此提升了StopIteration

然后,程序结束。