python / python/cpython

Optimize collection literals with leading null unpack idiom in bytecode, allows bare `BUILD_SET 0`

Ouverte
#150,737 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

interpreter-core type-feature
Langage dominant
Python
Étoiles
77.2k
Forks
35.9k
Métriques de merge des PR
Métriques de PR en attente

Description

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 set set())
  • Remove performance penalty of incremental construction between 0-to-1/1-to-0 elements for set and tuple literals 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:

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

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par examiner empty_unpack_benchmark.py et les exemples d’implémentation liés dans la proposition, puis inspectez la PR liée gh-150812 ainsi que la discussion Discourse associée. Le travail est considéré comme terminé lorsque les cas proposés de littéraux de collection évitent les mises à jour vides redondantes tout en préservant le comportement documenté et les améliorations des benchmarks.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
compilers
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
25/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.