这是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()
答案 0 :(得分:1)
经过一番挖掘后,我在这里发布了答案。
首先,我们需要了解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
然后,程序结束。