Optimize collection literals with leading null unpack idiom in bytecode, allows bare `BUILD_SET 0`
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 77.2k
- Forks
- 35.9k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
Feature or enhancement
Proposal:
Performance was discussed at various times within PEP 802 topic, submitting this proposal as the PEP is unlikely to be accepted. This is intended as an advanced escape-hatch not overlapping with the main reasons for PEP 802.
Goal:
- Remove performance penalty of
ast.unparse(ast.Set(elts=[]))({*()}can be used in advanced cases and will not change recommended way to write empty setset()) - Remove performance penalty of incremental construction between 0-to-1/1-to-0 elements for
setandtupleliterals without special case considerations (e.g.x = *(),pre-seeded tuple literal without trailing comma pitfall) - Keep implementation simple/self-contained in bytecode generation, avoiding any AST changes to language
- Near-zero performance impact to bytecode generation (improves subsequent bytecode optimizations of target case)
Implementation examples:
- During first AST -> bytecode pass: https://github.com/python/cpython/commit/67742d92c411a93e7692f761ffeb3af75ba1ff87#diff-6d58b0ddc066ad12ebc378b62c4189335bd57c83aece11072c76fd86a78a1a4a
- During bytecode-only optimization step: https://github.com/python/cpython/commit/f857d88ef3aac90deadf438625211040e73df832#diff-3cbf15668c31488528b7ab0f903c674a0ecf550f4f53c1be6cf8cd965246c2a0
Micro-benchmark
Run on windows x64bit release build: empty_unpack_benchmark.py
Compile time
Targeted cases:
| Benchmark | Main | Flowgraph only | Codegen leading only |
|---|---|---|---|
[*()] |
1.450 ms / 1.000x | 1.393 ms / 0.961x | 1.378 ms / 0.950x |
{*()} |
1.530 ms / 1.000x | 1.488 ms / 0.973x | 1.467 ms / 0.959x |
(*(),) |
1.916 ms / 1.000x | 1.842 ms / 0.962x | 1.832 ms / 0.956x |
x = *(), |
1.139 ms / 1.000x | 1.088 ms / 0.955x | 1.055 ms / 0.927x |
xychart-beta
title "Compile targeted mean ratio vs main"
x-axis [Main, Flowgraph, Leading]
y-axis "Ratio" 0 --> 1.01
bar [1.000, 0.963, 0.948]
Control near-miss case comparisons moved less than +/-1% and are attributed to noise.
Runtime
The set() versus {*()} comparison is especially useful because it changes qualitatively across the two branches (~6.3% slower to ~29.5% faster):
| Branch | set() mean (ns) |
{*()} mean (ns) |
{*()} vs set() |
|---|---|---|---|
| Main | 54.14 | 57.53 | 1.063x |
| Flowgraph only | 53.49 | 38.01 | 0.711x |
| Codegen leading only | 55.44 | 39.00 | 0.704x |
Before this change, {*()} was paying for a redundant empty update and ended up slower than the constructor call. After the change, {*()} compiles down to a direct BUILD_SET 0; RETURN_VALUE path, while set() still has to load the global and perform a zero-argument call.
Has this already been discussed elsewhere?
I have already discussed this feature proposal on Discourse
Links to previous discussion of this feature:
https://discuss.python.org/t/pep-802-display-syntax-for-the-empty-set/101676/237
https://discuss.python.org/t/pep-802-display-syntax-for-the-empty-set/101676/216
https://discuss.python.org/t/pep-802-display-syntax-for-the-empty-set/101676/3
Linked PRs
- gh-150812
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne mit der Durchsicht von empty_unpack_benchmark.py und den in der Proposal verlinkten Implementierungsbeispielen und untersuche anschließend den verlinkten PR gh-150812 sowie die zugehörige Discourse-Diskussion. Als erledigt gilt die Aufgabe, wenn die vorgeschlagenen Collection-Literal-Fälle redundante leere Aktualisierungen vermeiden und dabei das dokumentierte Verhalten sowie die Verbesserungen der Benchmarks erhalten bleiben.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- python
- Bereich
- compilers
- Issue-Typ
- Feature
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Veraltet
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 25/100