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 — json.dump(x,f) is much slower than f.write(json.dumps(x)) · Issue #129711 · python/cpython

json.dump(x,f) is much slower than f.write(json.dumps(x)) #129711

New issue
Copy link
New issue
Copy link
Open
Open
json.dump(x,f) is much slower than f.write(json.dumps(x))#129711
Copy link
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirperformancePerformance or resource usagePerformance or resource usagestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@wjmelements
wjmelements
opened on Feb 6, 2025
Issue body actions

Bug report

Bug description:

Experimentally I measured a huge performance improvement when I switched my code from

json.dump(x, f, **)

to

f.write(json.dumps(x, **))

Method

I essentially wrote the same contents to different files sequentially and measured the total amount of time taken. The json contents had 1, 300, and 400 entries per level, and 1, 5, and 6 levels of depth. There's quite a level of variance here but this wasn't what I was trying to measure in the first place. I discovered this by chance, so forgive the lack of precision. I also don't have the source code anymore because I wasn't originally planning to report this discovery.

Results

File Size Consecutive Files dump µs dumps µs
74 1 508 581
74 2 520 541
74 4 1153 1151
74 8 1930 1750
39184 1 6363 1086
39184 2 11261 1821
39184 4 38126 3521
39184 8 80411 6466
468218 1 82821 11921
468218 2 150234 38017
468218 4 302357 42137
468218 8 573450 78545

Conclusion

A cursory investigation into the cpython code suggests that the slow part is the sequential writing of the iterencode yield. The chunks are quite small.

CPython versions tested on:

3.10

Operating systems tested on:

macOS

Linked PRs

  • Draft: gh-129711: Reduce number of yield statements in json encoder #130076

Activity

Next
  1. wjmelements
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Feb 6, 2025
  2. tomasr8
    added this to JSON issueson Feb 6, 2025
  3. pochmann3 commented on Feb 6, 2025

    @pochmann3
    pochmann3
    on Feb 6, 2025
    Contributor
    More actions

    Old issue that I think partially covers this (wasn't about depth, though):

    #56343

  4. pochmann3 commented on Feb 6, 2025

    @pochmann3
    pochmann3
    on Feb 6, 2025
    Contributor
    More actions

    Demo with deep nesting:

     37.3 ms  json.dump(x, f)
      0.3 ms  f.write(json.dumps(x))
     36.2 ms  json.dump(x, f)
      0.3 ms  f.write(json.dumps(x))
     36.2 ms  json.dump(x, f)
      0.3 ms  f.write(json.dumps(x))
    
    from timeit import timeit
    
    setup = '''
    import io, json
    f = io.StringIO()
    x = [0] * 1000
    for i in range(900):
        x = [x]
    '''
    
    for code in [
        'json.dump(x, f)',
        'f.write(json.dumps(x))',
    ] * 3:
        t = timeit(code, setup, number=10) * 100
        print(f'{t:5.1f} ms  {code}')

    Attempt This Online!

    Reacted by Tomas R.
  5. eendebakpt
    added
    performancePerformance or resource usagePerformance or resource usage
    on Feb 7, 2025
  6. picnixz
    added
    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
    extension-modulesC modules in the Modules dirC modules in the Modules dir
    on Feb 7, 2025
  7. pganssle commented on Feb 7, 2025

    @pganssle
    pganssle
    on Feb 7, 2025
    Member
    More actions

    I think the main difference between these code paths is that when you are incrementally encoding the JSON, CPython uses the Python version of make_encoder, whereas when the encoding is done all at once, CPython uses the C implementation from _json.c. If you modify @pochmann3's example to disable the C encoder:

    from timeit import timeit
    import json.encoder
    json.encoder.c_make_encoder = None
    
    setup = '''
    ...

    The two functions perform the same:

     37.9 ms  json.dump(x, f)
     37.3 ms  f.write(json.dumps(x))
     36.7 ms  json.dump(x, f)
     38.0 ms  f.write(json.dumps(x))
     35.0 ms  json.dump(x, f)
     35.4 ms  f.write(json.dumps(x))
    

    I'm guessing that the performance would be a lot closer by impementing an incremental encoder in C.

  8. pochmann3 commented on Feb 9, 2025

    @pochmann3
    pochmann3
    on Feb 9, 2025
    Contributor
    More actions

    the primary difference stems from json.dump performing incremental writes using Python's iterencode, whereas json.dumps utilizes the C-optimized encoder

    I haven't looked at the C version, but dump was that slow in my demo mostly because of the recursion, not because it uses Python.

  9. eendebakpt commented on Feb 13, 2025

    @eendebakpt
    eendebakpt
    on Feb 13, 2025
    Contributor
    More actions

    @Ghost4 Performance related improvements are often a trade-off between performance and added code complexity. Here the gain is significant, but it is not yet clear how complex a C implementation would be. Also it is not entirely clear what the reason is for the performance differences: C vs. Pytho, recursion, or something else.

    Guidelines for making PRs can be found at https://devguide.python.org/

  10. eendebakpt
    added a commit that references this issue on Jun 15, 2026

    pythongh-129711: Add a streaming C implementation of the JSON encoder

    baf0b93
  11. eendebakpt
    added 2 commits that reference this issue on Aug 11, 2026

    pythongh-129711: Add a streaming C implementation of the JSON encoder

    7eb7a4d

    pythongh-129711: Factor out circular-marker and dict-key helpers in _…

    72e86c4
  12. 5 remaining items

  13. eendebakpt
    added 11 commits that reference this issue on Aug 12, 2026

    pythongh-129711: Add tests for the streaming JSON encoder

    58a11f5

    pythongh-129711: Add a streaming C implementation of the JSON encoder

    0a53763

    pythongh-129711: Add tests for the streaming JSON encoder

    f293cd3

    pythongh-129711: Factor out circular-marker and dict-key helpers in _…

    40ed013

    pythongh-129711: Add a streaming C implementation of the JSON encoder

    d0ad68e

    pythongh-129711: Add tests for the streaming JSON encoder

    2541a17

    pythongh-129711: Refactor _json encoder helpers for reuse

    4aafd9e

    pythongh-129711: Add a streaming C implementation of the JSON encoder

    c676a7c

    pythongh-129711: Add tests for the streaming JSON encoder

    1a3d569

    pythongh-129711: Add a streaming C implementation of the JSON encoder

    0e44342

    pythongh-129711: Add tests for the streaming JSON encoder

    4ce308e
  14. eendebakpt
    added 4 commits that reference this issue on Aug 22, 2026

    pythongh-129711: Add a no-escape fast path to the _json str escapers

    1903996

    pythongh-129711: Add a no-escape fast path to the _json str escapers

    c131104

    pythongh-129711: Add a no-escape fast path to the _json str escapers

    9a9172b

    pythongh-129711: Add a no-escape fast path to the _json str escapers

    e32789e
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

    extension-modulesC modules in the Modules dirC modules in the Modules dirperformancePerformance or resource usagePerformance or resource usagestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    • JSON issues
      Status
      No status
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402520 — 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.