Another day, another blog post about KDToolBox,KDAB's collection of miscellaneous useful C++ classes and stuff.
Today, we'll talk about ways to throttle your signal/slots connections -- in other words, how to activate a slot less often than the emission rate of the signal it's connected to. The usual reason why you may want something like this is performance. Invoking a slot at a high frequency may be too expensive for your application, so you need to rate-limit the slot's activation.
That sounds very simple to achieve. All you need is love a timer and a little logic to (re)start the timer when a signal is received, then actually trigger the slot when the timer fires. However, as for many things, the devil is in the details.
In the industry, these rate-limiting behaviors have well-established names and behaviors: throttlers and debouncers (see here for some excellent examples).
A throttler calls the slot only once every X milliseconds, no matter the input frequency of the signal. Use case: filtering out input events which may occur at a very high frequency (example: mouse events). An expensive operation triggered by these events (like scrolling and repainting) can be performed less often.
A debouncer activates the slot only once, after a timeout / grace period calculated since the last signal emission. In other words, if a signal keeps coming, the slot is not activated. Use case: a search box that actually starts searching only after the user stops typing (that is, after a short timeout since the last user input).
Furthermore, throttlers and debouncers can be trailing or leading.
Trailing means that the throttler/debouncer does not activate the slot immediately, but waits until its own timeout occurs before activating.
Leading means to activate the slot as soon as the throttler/debouncer itself is activated, and does not trigger again until the timeout occurs (and only if another signal is received in the meanwhile).
To watch this video on our website please or view it directly on YouTube
Throttlers and Debouncers Usage
Their usage is very simple. First and foremost, create an object of the right kind and set it up:
// trailing throttler, rate limiting at 1 emission every 100msKDSignalThrottler *throttler =newKDSignalThrottler(parent);throttler->setTimeout(100ms);
Then, place the throttler as an "intermediary" object between the signal that should be rate-limited and the slot that needs to be activated. You need to connect your signal to the throttle() slot of the throttler and the throttler's own triggered() signal to the actual slot:
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications. In addition to being leading experts in Qt, C++ and 3D technologies for over two decades, KDAB provides deep expertise across the stack, including Linux, Rust and modern UI frameworks. With 100+ employees from 20 countries and offices in Sweden, Germany, USA, France and UK, we serve clients around the world.
2 Comments
7 - Apr - 2021
Julien
That's indeed useful from time to time !
What about making it even easier to use, with a single function call, similar to the static QObject::connect :
This could automatically instantiate a KDSignalThrotller, connect the signal and slot to it, and make sure the throtller is deleted as soon as either connection is broken.
As a user, this would make throttled connection as easy and safe to use as a regular connection.
12 - Apr - 2021
Giuseppe D'Angelo
Hi,
That sounds like a nice idea. Mind filing it as a suggestion on GitHub? :) Thanks.
Giuseppe D’Angelo
Senior Software Engineer
Senior Software Engineer at KDAB. Giuseppe is a long-time contributor to Qt, having used Qt and C++ since 2000, and is an Approver in the Qt Project. His contributions in Qt range from containers and regular expressions to GUI, Widgets, and OpenGL. A free software passionate and UNIX specialist, before joining KDAB, he organized conferences on opensource around Italy. He holds a BSc in Computer Science.
Our hands-on Modern C++ training courses are designed to quickly familiarize newcomers with the language. They also update professional C++ developers on the latest changes in the language and standard library introduced in recent C++ editions.
2 Comments
7 - Apr - 2021
Julien
That's indeed useful from time to time !
What about making it even easier to use, with a single function call, similar to the static QObject::connect :
This could automatically instantiate a KDSignalThrotller, connect the signal and slot to it, and make sure the throtller is deleted as soon as either connection is broken.
As a user, this would make throttled connection as easy and safe to use as a regular connection.
12 - Apr - 2021
Giuseppe D'Angelo
Hi,
That sounds like a nice idea. Mind filing it as a suggestion on GitHub? :) Thanks.