-
Notifications
You must be signed in to change notification settings - Fork 823
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Static Widget Refresh Slows Down After Every Update #5156
Comments
In all honesty, I don't think you are seeing what you think you are seeing. Your QR code generation is cpu-bound, which means that unless you run it in a threaded worker it will block the async event loop -- and your app will become unresponsive. You almost certainly want a threaded worker. If that doesn't get you anywhere, I'd suggest writing a MRE. The simplest possible app that implements the qr code as you type functionality. That would give us a better starting point. I'm sure it is possible to implement this while keeping the UI responsive as you would expect. |
Does this do what you are looking for? import io
from textual import on, work
from textual.app import App, ComposeResult
from textual.widgets import Static, Input
import qrcode
class QRApp(App):
def compose(self) -> ComposeResult:
yield Input()
yield Static(id="qr")
@on(Input.Changed)
def on_input_changed(self, event: Input.Changed):
self.generate_qr(event.value)
def refresh_qr(self, qr: str) -> None:
self.query_one("#qr").update(qr)
@work(thread=True)
def generate_qr(self, url: str):
qr = qrcode.QRCode(
version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, border=0
)
qr.add_data(url)
f = io.StringIO()
qr.print_ascii(out=f)
self.call_from_thread(self.refresh_qr, f.getvalue())
if __name__ == "__main__":
app = QRApp()
app.run() |
Thank you for your suggestion. After modifying it in various ways, I found the issue with my code. It is basically written like this: 🐍 modified scriptimport io
import qrcode
from textual import on, work
from textual.app import App, ComposeResult
from textual.widgets import Input, Static
class QRApp(App):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.buffer = io.StringIO()
def compose(self) -> ComposeResult:
yield Input()
yield Static(id="qr")
@on(Input.Changed)
def on_input_changed(self, event: Input.Changed):
self.generate_qr(event.value)
def refresh_qr(self, qr: str) -> None:
self.query_one("#qr").update(qr)
@work(thread=True)
def generate_qr(self, url: str):
qr = qrcode.QRCode(
version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, border=0
)
qr.add_data(url)
f = self.buffer
f.truncate(0)
qr.print_ascii(out=f)
f.seek(0)
self.call_from_thread(self.refresh_qr, f.read())
if __name__ == "__main__":
app = QRApp()
app.run() @@ -7,6 +7,10 @@ from textual.widgets import Input, Static
class QRApp(App):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.buffer = io.StringIO()
+
def compose(self) -> ComposeResult:
yield Input()
yield Static(id="qr")
@@ -24,9 +28,11 @@ class QRApp(App):
version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, border=0
)
qr.add_data(url)
- f = io.StringIO()
+ f = self.buffer
+ f.truncate(0)
qr.print_ascii(out=f)
- self.call_from_thread(self.refresh_qr, f.getvalue())
+ f.seek(0)
+ self.call_from_thread(self.refresh_qr, f.read())
if __name__ == "__main__": Producing a new buffer is obviously faster than truncating the same one over and over. Classic premature optimization on my side. Thank you @willmcgugan for your lightning-fast help! |
Don't forget to star the repository! Follow @textualizeio for Textual updates. |
Hi!
Love your library so much! ❤️
Upon creating a QRCode widget, I noticed that its refresh time increases with each subsequent call of
Static().update(qrcode)
.So, I threw some sort of benchmark together:
additional requirements
🐍 Benchmark Script
The following plots show the time per QRCode calculation ("run") over runs. Please note the ranges of the y-axes.
> python benchmark.py cli
This is the baseline plot with
qrcode
printing the QRCode ASCII chars to stdout:> python benchmark.py app
For this plot, the QRCode ASCII chars were given to the
Static().update()
method, which then updated the widget. I suspect that the spikes are related to the layout refreshing.In the actual app, QRCodes are not spammed as in this example script, but updated on changed input by the user. It is still clearly noticable when typing a few more (~50) chars. Most importantly, the lag seems to persist even after typing stops and no new QRCode is created.
Unfortunately, I don't know how to resolve this. 🤷
What do you think?
textual diagnose
Textual Diagnostics
Versions
Python
Operating System
Terminal
Rich Console options
The text was updated successfully, but these errors were encountered: