Skip to content

Pasting in new REPL is slow #130328

Description

@natedogith1

Bug report

Bug description:

Pasting large blocks of text in the new REPL is slow. Tested by pasting the following string (3035 characters):

test value
"""1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"""

When using the old repl (started via $env:PYTHON_BASIC_REPL="true"; python in powershell), pasting the string is near immediate. When using the new repl (started via python in powershell), pasting the string takes 15 seconds.

The closed issue #119517 also mentioned some pasting performance issues, though that was for Linux with significantly more characters.

CPython versions tested on:

3.13

Operating systems tested on:

Windows

Linked PRs

Activity

  1. StanFromIreland commented on Feb 20, 2025

    @StanFromIreland
    Member

    Possibly a windows issue, something to do with powershell? On linux (main branch build) it pastes as expected, instantly.

    cc windows expert @zooba

  2. zooba commented on Feb 20, 2025

    @zooba
    Member

    It's no good looking at me, I know nothing about the new repl (other than that I've suggested a couple of times that it should stop using ctypes and use native code instead, which could be the cause of any performance issue).

    @pablogsal @lysnikolaou @ambv are code owners for the REPL.

  3. natedogith1 commented on Feb 21, 2025

    @natedogith1
    Author

    I also see this when python is started from the win-r run dialog.

    Tested some other environments, using the first 604 lines of this copy of Frankenstein (32,003 characters) (same as #119517 did). WSL old REPL takes ~2 seconds. WSL new REPL takes ~4 seconds, Powershell old REPL takes ~1 second. Powershell new REPL takes ~55 seconds for just the first 25 lines to appear; when pasting only the first 25 lines (659 characters) it takes ~2 seconds.

  4. added
    performancePerformance or resource usage
    stdlibStandard Library Python modules in the Lib/ directory
    on Feb 21, 2025
  5. devdanzin commented on Feb 22, 2025

    @devdanzin
    Member

    I think it's caused by the Windows console reading one character at a time from input:

    rec = INPUT_RECORD()
    read = DWORD()
    if not ReadConsoleInput(InHandle, rec, 1, read):
    raise WinError(GetLastError())

    But I don't know enough about ctypes or Windows API to know how to increase that value, naively using larger ints results in errors.

    cc @DinoV, who implemented the Windows console.

  6. devdanzin commented on Feb 22, 2025

    @devdanzin
    Member

    I was able to make ReadConsoleInput read 1024 chars at a time and also reduced self.console.wait() in Reader.handle1 from 100 to 0.1. That reduced time to paste the content from first post from 10s to 6s, which isn't a significant improvement given the numbers from WSL and basic REPL.

  7. devdanzin commented on Feb 22, 2025

    @devdanzin
    Member

    #124119 seems to improve things, but nowhere near WSL numbers.

    Edit: With that PR, time to past the sample from first post goes from 10s to 2.5s. Reading 32 chars of input instead of 1 and reducing Reader.console.wait from 100 to 10 further reduces time to 1.7s. So we can paste 5x faster than current version, which pales compared to the near instant paste in WSL.

  8. devdanzin commented on Feb 23, 2025

    @devdanzin
    Member

    Can you check whether devdanzin#1 speeds up pasting significantly for you?

    It's a quick and dirty POC built on top of #124119 that:

    • Batches event processing;
    • Reads 32 chars from input instead of 1;
    • Enables virtual terminal (from the mentioned PR);
    • Reduces Reader.console.wait() from 100 to 10.

    It fails some tests and the code is ugly, but if it makes things better we can try to improve on this.

  9. devdanzin commented on Feb 28, 2025

    @devdanzin
    Member

    Please test the #130677 PR to check whether it significantly improves pasting time for you.

  10. chris-eibl commented on Apr 24, 2025

    @chris-eibl
    Member

    The reason why pasting is so slow on Windows (especially in the legacy console case where virtual terminal mode - and thus bracketed paste - is disabled):

    while True:
    # We use the same timeout as in readline.c: 100ms
    self.run_hooks()
    self.console.wait(100)
    event = self.console.get_event(block=False)

    and

    def wait(self, timeout: float | None) -> bool:
    """Wait for an event."""
    # Poor man's Windows select loop
    start_time = time.time()
    while True:
    if msvcrt.kbhit(): # type: ignore[attr-defined]
    return True
    if timeout and time.time() - start_time > timeout / 1000:
    return False
    time.sleep(0.01)

    It is interesting, that msvcrt.kbhit() returns True in case of pasting, but if that weren't the case, we'd hit the 100ms timeout and would be even way slower. However, msvcrt.kbhit() is very slow in case of the legacy console, and it is called at least twice as often, because we get a key up and a key down event - but only a key down event in the virtual terminal case. If the pasted input contains upper case letters, we additionally get a "shift key pressed" event - so in the worst case, msvcrt.kbhit() gets called 3 times more often (and each call is slower).

    Output of python.bat -m cProfile -m _pyrepl when pasting the "test value" given in the OP for a legacy console:

       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
         50/1    0.010    0.000   17.202   17.202 {built-in method builtins.exec}
            1    0.000    0.000   17.202   17.202 <frozen runpy>:201(run_module)
            1    0.000    0.000   17.199   17.199 <frozen runpy>:65(_run_code)
            1    0.000    0.000   17.199   17.199 __main__.py:1(<module>)
            1    0.000    0.000   17.112   17.112 main.py:24(interactive_console)
            1    0.000    0.000   17.112   17.112 simple_interact.py:99(run_multiline_interactive_console)
            5    0.000    0.000   17.111    3.422 readline.py:375(multiline_input)
            5    0.004    0.001   17.111    3.422 reader.py:741(readline)
         3090    0.036    0.000   17.103    0.006 reader.py:694(handle1)
         6210    0.013    0.000   13.714    0.002 windows_console.py:523(wait)
         6236   13.433    0.002   13.433    0.002 {built-in method msvcrt.kbhit}
    

    Here the relevant line in case of virtual terminal:

      3270    0.554    0.000    0.554    0.000 {built-in method msvcrt.kbhit}
    

    The fix is to use WaitForSingleObject

        def wait(self, timeout: float | None) -> bool:
            """Wait for an event."""
            ret = WaitForSingleObject(InHandle, int(timeout))
            if ret == WAIT_FAILED:
                raise WinError(ctypes.get_last_error())

    which speeds up especially the legacy console (times in seconds):

    legacy terminal virtual terminal
    before 15.6 0.89
    after 1.8 0.26

    Note, see also #132440 (comment):

    • legacy terminal: manually start cmd.exe. Timings gotten by pasting
    import time
    t1 = time.time()
    <"test value" given in the OP>
    print(time.time() - t1)
    
    • virtual terminal: power shell via Windows terminal. Timings gotton by temporarily patching commands.py:
    import time
    class enable_bracketed_paste(Command):
        def do(self) -> None:
            self.reader.bp_begin = time.perf_counter()
            self.reader.paste_mode = True
            self.reader.in_bracketed_paste = True
    
    class disable_bracketed_paste(Command):
        def do(self) -> None:
            print("bracketed_paste took %5.2f s" % (time.perf_counter() - self.reader.bp_begin, ))
            self.reader.paste_mode = False
            self.reader.in_bracketed_paste = False
            self.reader.dirty = True
  11. chris-eibl commented on Apr 24, 2025

    @chris-eibl
    Member

    Because pasting is so slow (especially in case of a legacy console), I've marked this as a release blocker.

  12. 18 remaining items

  13. chris-eibl commented on May 9, 2025

    @chris-eibl
    Member

    @ambv I gave it a try and came up with #133728. Works for me in Windows and WSL in legacy and vt terminals and is as fast as bracketed pasting in paste mode (F3).

  14. added a commit that references this issue on May 25, 2025
  15. added a commit that references this issue on May 25, 2025
  16. added 2 commits that reference this issue on May 25, 2025
  17. added a commit that references this issue on May 25, 2025
  18. added a commit that references this issue on May 25, 2025
  19. stonebig commented on May 26, 2025

    @stonebig

    will it be backported to 3.13 too ?

  20. ambv commented on May 26, 2025

    @ambv
    Contributor

    No, this is a performance optimization with pretty large internal changes required.

  21. added 2 commits that reference this issue on Jul 12, 2025
  22. added 2 commits that reference this issue on Aug 4, 2025
  23. added 2 commits that reference this issue on Jun 2, 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

    OS-windowsperformancePerformance or resource usagerelease-blockerstdlibStandard Library Python modules in the Lib/ directorytopic-replRelated to the interactive shelltype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions