Skip to content

High CPU / UI input lag when connected to a remote ComfyUI (1.51 regression) — asyncio loop pumped on the GUI thread #2534

Description

@carlogerli00-collab

Summary

Since updating to 1.51.0, Krita sits at a constant ~14% CPU while idle and has noticeable UI input lag (canvas pan/zoom, brush, trackpad pinch-zoom stutters/freezes) whenever the plugin is connected to a remote ComfyUI server. Disconnecting the server makes the lag disappear instantly; reconnecting brings it back. This did not happen on 1.50.0 with the exact same remote setup.

Setup

  • Krita 5.x, macOS (Apple Silicon / M3)
  • krita-ai-diffusion 1.51.0
  • ComfyUI is remote: a RunPod pod reached through an HTTPS reverse proxy (*.proxy.runpod.net) → higher latency and an occasionally-flaky websocket. A local/localhost ComfyUI does not seem affected.
  • Full disclosure: I keep two tiny local patches in network.py (force HTTP/1.1 for the proxy) and comfy_client.py (retry upload/download). eventloop.py is unmodified. I don't believe these cause the issue (it's clearly tied to the event loop being pumped on the GUI thread), but mentioning for transparency.

Profiling

sample <krita-pid> taken while idle and connected shows the time dominated by the asyncio↔Qt pump on the main/GUI thread:

  • the 20 ms QTimer in eventloop.pyprocess_python_events()_loop.run_forever(),
  • with deeply nested QTimer::timerEvent → PyQt slot dispatch frames.

The active _handle_messages() websocket task (+ scheduler polling) appears to keep the loop producing ready callbacks on every tick, so the ~50 Hz main-thread pump does real work continuously and contends with GUI/input event delivery → the lag. When disconnected there is no async activity, the pump idles, and CPU/lag return to normal.

Likely cause / possible directions

The asyncio loop is pumped on the GUI thread every 20 ms via run_forever(). With a remote (higher-latency) ComfyUI the websocket/poll tasks keep it busy, so the main thread is starved. Possible directions:

  • Skip/throttle the pump when there are no ready callbacks (avoid run_forever() doing work every tick when idle), or make pumping event-driven instead of a fixed 20 ms timer.
  • Run the asyncio loop on a dedicated thread (or adopt qasync) so network I/O doesn't compete with the GUI thread.
  • If 1.51 changed/added periodic polling (scheduler poll_rate, connection keepalive, model refresh), consider widening the interval or making it event-driven.

Happy to share the full sample output or test any patch. Thanks for the excellent plugin! 🙏

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions