Uh oh!
There was an error while loading. Please reload this page.
GH-96793: Specialize FOR_ITER for generators. - #98772
Conversation
markshannon
commented
Oct 31, 2022
There is a bug in this. It doesn't set the |
markshannon
commented
Oct 31, 2022
https://github.com/python/cpython/compare/main...faster-cpython:cpython:specialize-for-iter-gen-handle-exc-stack?expand=1 |
| frame->frame_obj = NULL; | ||
| frame->prev_instr = _PyCode_CODE(code) - 1; | ||
| frame->is_entry = false; | ||
| frame->yield_offset = 0; |
There was a problem hiding this comment.
Why is this called "yield_offset", is it not the relative offset to jump by when the generator is exhausted? (the same as the arg to FOR_ITER?)
There was a problem hiding this comment.
Because it's the offset for YIELD_VALUE to return to relative to RETURN_VALUE
https://github.com/python/cpython/pull/98772/files#diff-c22186367cbe20233e843261998dc027ae5f1f8c0d2e778abfa454ae74cc59deR2087
kumaraditya303
commented
Nov 1, 2022
You can run https://github.com/python/pyperformance/blob/main/pyperformance/data-files/benchmarks/bm_generators/run_benchmark.py, it is specifically designed to benchmark generators (microbenchmark). |
I'll run that benchmark if pyperformance ever does another release. |
I'm seeing a 35% speedup on this benchmark: Tree iteratorimporttimeitclassTree:
def__init__(self, left, value, right):
self.left=leftself.value=valueself.right=rightdef__iter__(self):
ifself.left:
foriteminself.left:
yielditemyieldself.valueifself.right:
foriteminself.right:
yielditemdeftree(input: range) ->Tree|None:
n=len(input)
ifn==0:
returnNonei=n//2returnTree(tree(input[:i]), input[i], tree(input[i+1:]))
defsetup():
globaliterableassertlist(tree(range(10))) ==list(range(10))
iterable=tree(range(100000))
print(timeit.timeit("for _ in iterable: pass", "setup()", globals=globals(), number=10))Note that this uses And a 36% speedup on this one: Flat iteratorimporttimeitclassRangeWrapper:
def__init__(self, n):
self.r=range(n)
def__iter__(self):
foriteminself.r:
yielditemdefsetup():
globaliterableiterable=RangeWrapper(1000000)
print(timeit.timeit("for _ in iterable: pass", "setup()", globals=globals(), number=10))Comparing the fastest of 6 runs for main and this PR. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
Performance results seem to be just noise. I suspect there aren't enough uses of generators in the benchmark suite for this to make a difference.
for gen():, and awaiting coroutines,await coro()#96793