prompt-toolkit / prompt-toolkit/python-prompt-toolkit

patch_stdout is surprisingly slow

Open
#682 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Python
Stars
10.6k
Forks
815
PR merge metrics
No merged PRs in 30d

Description

patch_stdout slows down the program (by ~5x) if there's a lot of output which seems really large considering that what it's trying to do conceptually doesn't seem too complicated.

from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.eventloop.defaults import use_asyncio_event_loop
from prompt_toolkit.patch_stdout import patch_stdout
from prompt_toolkit.shortcuts import CompleteStyle
from prompt_toolkit.shortcuts.prompt import prompt
from threading import Thread
from prompt_toolkit.application import get_app

import sys

def spam_print():
  i = 1
  while True:
    print("This is spam", i)
    i += 1
    if i == 1000:
      try:
        get_app(raise_exception=True).exit(exception=KeyboardInterrupt())
      except:
        sys.exit(0)
      return

thread = None

while True:
  with patch_stdout():
  # with open("/dev/null"):
    if not thread:
      thread = Thread(target=spam_print)
      thread.start()
    prompt("> ", rprompt="test", complete_style=CompleteStyle.MULTI_COLUMN,
            completer=WordCompleter(list(chr(c) * 20 for c in range(ord("a"), ord("z")))))

time python3 test.py

Without patch_stdout: ~0.2s
With patch_stdout: ~1s (including getting hit by #681).

Attached captured profile but viewing it in snakeviz doesn't seem to immediately point me to the source of performance issues (aside from that it does look like there's a hotspot). Maybe run_until_complete in patch_stdout prints 1 line at a time instead of all lines that have been buffered?

profile.bin.zip

profile_without_patch_stdout.bin.zip

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the supplied test.py reproduction with and without patch_stdout, then inspect the patch_stdout entry point and compare the attached profile captures. Done means reducing the roughly fivefold slowdown for buffered output without changing patch_stdout's behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.