【发布时间】:2017-08-31 22:31:27
【问题描述】:
在当今多核、多线程 CPU(我笔记本中的 CPU 有两个内核,每个内核两个线程)的编程世界中,编写能够利用提供的硬件功能的代码越来越有意义。像 go(lang) 这样的语言的诞生是为了让程序员更容易通过生成多个“独立”进程来加速应用程序,以便稍后再次同步它们。
在与 Python 中的生成器函数联系的上下文中,我预计此类函数将使用在后续项目请求之间传递的空闲时间来准备下一个收益以立即交付,但似乎不是这样 - 至少所以我对运行下面提供的代码所得到的结果的解释。
更让我困惑的是,即使生成器已经交付了所有项目,生成器函数的调用者也必须等到函数完成处理所有剩余的指令。
是否有任何我目前看不到的明确原因,为什么要使用生成器 函数不在 yield 请求之间的空闲时间运行代码 超过请求的产量,直到满足下一个产量指令,并且 甚至让调用者等待,以防所有物品都已送达?
这里是我使用的代码:
import time
startTime = time.time()
time.sleep(1)
def generatorFunctionF():
print("# here: generatorFunctionF() lineNo #1", time.time()-startTime)
for i in range(1,4):
print("# now: time.sleep(1)", time.time()-startTime)
time.sleep(1)
print("# before yield", i, time.time()-startTime)
yield i # yield i
print("# after yield", i, time.time()-startTime)
print("# now: time.sleep(5)", time.time()-startTime)
time.sleep(5)
print("# end followed by 'return'", time.time()-startTime)
return
#:def
def standardFunctionF():
print("*** before: 'gFF = generatorFunctionF()'", time.time()-startTime)
gFF = generatorFunctionF()
print("*** after: 'gFF = generatorFunctionF()'", time.time()-startTime)
print("*** before print(next(gFF)", time.time()-startTime)
print(next(gFF))
print("*** after print(next(gFF)", time.time()-startTime)
print("*** before time.sleep(3)", time.time()-startTime)
time.sleep(3)
print("*** after time.sleep(3)", time.time()-startTime)
print("*** before print(next(gFF)", time.time()-startTime)
print(next(gFF))
print("*** after print(next(gFF)", time.time()-startTime)
print("*** before list(gFF)", time.time()-startTime)
print("*** list(gFF): ", list(gFF), time.time()-startTime)
print("*** after: list(gFF)", time.time()-startTime)
print("*** before time.sleep(3)", time.time()-startTime)
time.sleep(3)
print("*** after time.sleep(3)", time.time()-startTime)
return "*** endOf standardFunctionF"
print()
print(standardFunctionF)
print(standardFunctionF())
给予:
>python3.6 -u "aboutIteratorsAndGenerators.py"
<function standardFunctionF at 0x7f97800361e0>
*** before: 'gFF = generatorFunctionF()' 1.001169204711914
*** after: 'gFF = generatorFunctionF()' 1.0011975765228271
*** before print(next(gFF) 1.0012099742889404
# here: generatorFunctionF() lineNo #1 1.0012233257293701
# now: time.sleep(1) 1.0012412071228027
# before yield 1 2.0023491382598877
1
*** after print(next(gFF) 2.002397298812866
*** before time.sleep(3) 2.0024073123931885
*** after time.sleep(3) 5.005511283874512
*** before print(next(gFF) 5.005547761917114
# after yield 1 5.005556106567383
# now: time.sleep(1) 5.005565881729126
# before yield 2 6.006666898727417
2
*** after print(next(gFF) 6.006711006164551
*** before list(gFF) 6.0067174434661865
# after yield 2 6.006726026535034
# now: time.sleep(1) 6.006732702255249
# before yield 3 7.0077736377716064
# after yield 3 7.0078125
# now: time.sleep(5) 7.007838010787964
# end followed by 'return' 12.011908054351807
*** list(gFF): [3] 12.011950254440308
*** after: list(gFF) 12.011966466903687
*** before time.sleep(3) 12.011971473693848
*** after time.sleep(3) 15.015069007873535
*** endOf standardFunctionF
>Exit code: 0
【问题讨论】:
-
不确定问题的第二部分(关于“必须等到生成器完成”)是什么意思。请澄清你的意思。
-
不要忘记
generators的相同机制可以是coroutines,例如x = yield 10,这在yielding10之后暂停,但分配发生在下一个send(5)或next(...)。你可能想看看asyncio -
这种行为会干扰定时数据,例如每天的服务器查询。按需交付的新数据通常比急切获取然后等待下一个请求到达的陈旧数据更受欢迎。
-
@BrenBarn:在生成器函数的代码离开循环后,生成器函数中可能会有更多命令。在我提供的示例代码中,其余代码不包含任何 yield 关键字,但是调用者必须等待项目的交付,直到代码被处理(在代码示例中 time.sleep(5) 秒长)。跨度>
-
@Claudio:我认为您误解了生成器是什么。它们是在 yield 语句(和 return 语句)之间暂停的函数。这就是他们所做的。它们并不意味着是在后台进行处理的某种优化方式。如果你写
time.sleep(5),那么当代码运行时它会休眠 5 秒。没有花哨的前瞻来查看将要发生什么;当您推进发电机时,它只会恢复。
标签: python multithreading iterator generator multicore