GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Improve performance by using reference stealing methods · Issue #150942 · python/cpython

Improve performance by using reference stealing methods #150942

New issue
Copy link
New issue
Copy link
Open
#155171
Open
Improve performance by using reference stealing methods#150942
#155171
Copy link
Labels
easyextension-modulesC modules in the Modules dirC modules in the Modules dirperformancePerformance or resource usagePerformance or resource usagetype-featureA feature request or enhancementA feature request or enhancement

Description

@eendebakpt
eendebakpt
opened on Jun 5, 2026
Issue body actions

Feature or enhancement

Proposal:

We can improve performance of cpython by using stealing methods (_PyList_AppendTakeRef, _PyDict_SetItem_Take2, PyTuple_FromPairSteal etc.) instead of the normal ones. Using stealing methods we typically avoid an incref/decref pair and sometimes error handling is simplified. We should only make changes where it makes a performance impact, the code is not more complex and the modules or methods affected are performance critical.

A list of possible cases (there might be more).

Location Module / context Helper
Modules/_csv.c:688 csv reader, per field _PyList_AppendTakeRef
Modules/pyexpat.c:472 pyexpat StartElement, per attribute _PyDict_SetItem_Take2
Modules/_elementtree.c:3351 ElementTree C accel attrib dict _PyDict_SetItem_Take2
Modules/_io/bytesio.c:577 io.BytesIO.readlines _PyList_AppendTakeRef
Modules/_io/iobase.c:756 io.IOBase.readlines (generic) _PyList_AppendTakeRef
Objects/frameobject.c:639 & 658 frame f_locals / vars() / tracing _PyList_AppendTakeRef
Modules/_pickle.c:5138 pickle Pickler memo copy _PyDict_SetItem_Take2
Modules/_io/textio.c:2337 & 2343 io.TextIOWrapper readline (multi-chunk) _PyList_AppendTakeRef
Modules/_asynciomodule.c:1213 asyncio future done-callback compaction _PyList_AppendTakeRef

Update: Most cases already have an open PR, for new ones please open a separate issue.

Linked PRs

  • gh-150942: Speed up re.findall and re.sub/subn result building #150943
  • gh-150942: Speed up json.loads array and object decoding #150945
  • gh-150942: Speed up csv.reader row building #150995
  • gh-150942: Speed up frame local item collection #151002
  • gh-151059: Use PyObject_CallMethodOneArg in datetime call_tzinfo_method #151062
  • gh-150942: Speed up ElementTree attribute parsing #151209
  • gh-150942: Optimize PicklerMemoProxy.copy() with _PyDict_SetItem_Take2 #151608
  • gh-150942: Speed up asyncio Future.remove_done_callback #153013
  • gh-150942: Speed up pyexpat attribute parsing #154860
  • gh-150942: Speed up BytesIO.readlines() using reference-stealing append #155171
  • gh-150942: Speed up IOBase.readlines #155304
  • gh-150942: Optimize stringlib split/splitlines with _PyList_AppendTakeRef #155922
  • gh-150942: Speed up re.split result building #155940
  • gh-150942: Improve performance of csv reader by using _PyList_AppendT… #155957
  • gh-150942: Speed up FrameLocalsProxy.values() #156055
  • gh-150942: Speed up Py_BuildValue dict construction #156199
Reacted by Sergey Miryanov, Ivy Xu, An Long, Wulian233, Xuanteng Huang, Timofei Ivankov and Seungki Kim
Reacted by stonebig

Activity

Next
  1. eendebakpt
    added
    type-featureA feature request or enhancementA feature request or enhancement
    performancePerformance or resource usagePerformance or resource usage
    easy
    on Jun 5, 2026
  2. eendebakpt
    added 2 commits that reference this issue on Jun 5, 2026

    pythongh-150942: Set issue number on the re speedup news entry

    bf25fc5

    pythongh-150942: Speed up json.loads array and object decoding

    4f4965f
  3. StanFromIreland
    added
    extension-modulesC modules in the Modules dirC modules in the Modules dir
    on Jun 5, 2026
  4. omkar-334 commented on Jun 5, 2026

    @omkar-334
    omkar-334
    on Jun 5, 2026
    Contributor
    More actions

    hi @eendebakpt @StanFromIreland can i work on a module , maybe csv or textio

  5. eendebakpt commented on Jun 5, 2026

    @eendebakpt
    eendebakpt
    on Jun 5, 2026
    ContributorAuthor
    More actions

    hi @eendebakpt @StanFromIreland can i work on a module , maybe csv or textio

    Sure! Try out, benchmark, test. If benchmarks show significant improvements you can open a PR, if not just report here briefly.

    Reacted by Omkar Kabde
  6. omkar-334
    added a commit that references this issue on Jun 6, 2026

    Merge branch 'main' into pythongh-150942-csv-appendtakeref

    1c00c00
  7. omkar-334 commented on Jun 6, 2026

    @omkar-334
    omkar-334
    on Jun 6, 2026
    Contributor
    More actions

    hi @eendebakpt , i've opned a PR for csv reader, since that has 1.08x speedup, matches your PR speedups....

    however, the benchmarks for io.BytesIO.readlines show that there is not a significant improvements

    Benchmark main my branch speedup
    bytesio_readlines_1m_8b 15.15 ms 15.29 ms 0.99x
    bytesio_readlines_500k_24b 7.66 ms 7.45 ms 1.03x
    bytesio_readlines_100k_256b 3.24 ms 3.20 ms 1.01x
    bytesio_readlines_2m_0b 16.33 ms 16.54 ms 0.99x
    bytesio_readlines_2m_8b 32.58 ms 31.97 ms 1.02x
    geomean 1.01x
    Benchmark script
    """Micro-benchmark for io.BytesIO.readlines result-list building."""
    
    from __future__ import annotations
    
    import argparse
    import io
    import json
    import statistics
    import sys
    import time
    from pathlib import Path
    
    
    def make_data(lines: int, payload_size: int) -> bytes:
        payload = b"x" * payload_size
        return b"".join(payload + b"\n" for _ in range(lines))
    
    
    def time_readlines(data: bytes) -> float:
        t0 = time.perf_counter_ns()
        io.BytesIO(data).readlines()
        return (time.perf_counter_ns() - t0) / 1e9
    
    
    def main() -> int:
        ap = argparse.ArgumentParser()
        ap.add_argument("--lines", type=int, default=200_000)
        ap.add_argument("--payload-size", type=int, default=24)
        ap.add_argument("--trials", type=int, default=15)
        ap.add_argument("--warmup", type=int, default=3)
        ap.add_argument("--label", default="run")
        ap.add_argument("--outdir", default="results/bytesio-readlines")
        args = ap.parse_args()
    
        data = make_data(args.lines, args.payload_size)
    
        for _ in range(args.warmup):
            time_readlines(data)
    
        trials = [time_readlines(data) for _ in range(args.trials)]
    
        outdir = Path(args.outdir)
        outdir.mkdir(parents=True, exist_ok=True)
        summary = {
            "label": args.label,
            "python": sys.executable,
            "lines": args.lines,
            "payload_size": args.payload_size,
            "trials": args.trials,
            "warmup": args.warmup,
            "input_bytes": len(data),
            "seconds": {
                "min": min(trials),
                "median": statistics.median(trials),
                "mean": statistics.fmean(trials),
                "stdev": statistics.pstdev(trials),
                "all": trials,
            },
            "lines_per_sec_at_min": args.lines / min(trials),
        }
        out = outdir / f"bench_{args.label}.json"
        out.write_text(json.dumps(summary, indent=2))
    
        s = summary["seconds"]
        print(
            f"{args.label}: min={s['min']*1000:.2f}ms median={s['median']*1000:.2f}ms "
            f"mean={s['mean']*1000:.2f}ms stdev={s['stdev']*1000:.2f}ms "
            f"lines/s@min={summary['lines_per_sec_at_min']:.2e}"
        )
        print(f"wrote {out}")
        return 0
    
    
    if __name__ == "__main__":
        raise SystemExit(main())

    do you think i should still make a pr for this

  8. omkar-334
    added a commit that references this issue on Jun 6, 2026

    Merge branch 'main' into pythongh-150942-csv-appendtakeref

    b29bdae
  9. tangyuan0821 commented on Jun 7, 2026

    @tangyuan0821
    tangyuan0821
    on Jun 7, 2026
    Contributor
    More actions

    Happy to try _asynciomodule.c — swap PyList_Append for
    _PyList_AppendTakeRef in future_add_done_callback.
    I'll benchmark first.

  10. corona10
    added 2 commits that reference this issue on Jun 7, 2026

    gh-150942: Speed up frame local item collection (gh-151002)

    253904f

    gh-150942: Speed up re.findall and re.sub/subn result building (gh-15…

    0f7dc2f
  11. tangyuan0821
    added a commit that references this issue on Jun 7, 2026

    pythongh-150942: Speed up asyncio future add_done_callback

    a6535d0
  12. 26 remaining items

  13. tkim602 commented on Aug 21, 2026

    @tkim602
    tkim602
    on Aug 21, 2026
    More actions

    Hi, I found an additional candidate in Python/modsupport.c::do_mkdict(), where Py_BuildValue() dictionary construction passes newly owned key/value references to PyDict_SetItem() and then immediately decrefs them. Using _PyDict_SetItem_Take2() avoids those INCREF/DECREF round trips. Targeted Py_BuildValue() dict microbenchmarks showed small but repeatable ~1–5% improvements across the tested cases.

    Opened #156199 for this.

  14. eendebakpt commented on Aug 22, 2026

    @eendebakpt
    eendebakpt
    on Aug 22, 2026
    ContributorAuthor
    More actions

    It seems all of the obvious cases have an open PR, so I am going to close the issue. For any new cases, please open a new issue.

  15. eendebakpt
    closed this as completedon Aug 22, 2026
  16. StanFromIreland commented on Aug 22, 2026

    @StanFromIreland
    StanFromIreland
    on Aug 22, 2026
    Member
    More actions

    I think we should keep this issue open however, unless you plan to move all the PRs?

  17. StanFromIreland
    reopened this on Aug 22, 2026
  18. picnixz
    marked Performance: Reduce refcount churn in csv.reader #156748 as a duplicate of this issue on Sep 1, 2026
  19. eendebakpt
    added a commit that references this issue on Oct 2, 2026

    gh-150942: Speed up BytesIO.readlines() using reference-stealing appe…

    b4197da
  20. eendebakpt
    closed this as completedin #155171on Oct 2, 2026
  21. picnixz
    reopened this on Oct 2, 2026
  22. picnixz commented on Oct 2, 2026

    @picnixz
    picnixz
    on Oct 2, 2026
    Member
    More actions

    Keeping it open because there are still PRs.

  23. catlover-bot
    added a commit that references this issue on Oct 4, 2026

    Merge upstream main and preserve FrameLocalsProxy.values() ownership

    028990a
  24. kevinprimeraquecreo-stack
    added this to Project_VKon Oct 18, 2026
  25. github-project-automation
    moved this to Todo in Project_VKon Oct 18, 2026
  26. github-project-automation
    moved this from Todo to In progress in Project_VKon Oct 18, 2026
  27. kevinprimeraquecreo-stack
    added this to Project_VKon Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    easyextension-modulesC modules in the Modules dirC modules in the Modules dirperformancePerformance or resource usagePerformance or resource usagetype-featureA feature request or enhancementA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.