# Timers:busy-waiting, busy-looping, spinning Busy-waiting is where your code periodically checks to see if it should do something. It's not a problem by itself, and the performance impact is only as large as the checks it's doing are complicated - but if they *are* complicated, or you're running a *lot* of these at the same time, they'll eat up a non-trivial amount of your frame time. For example, this code which is meant to check if a debug draw (or "debug helper" because the verb and the noun are the same and that's annoying) has timed out and should stop being drawn: ```gdscript OMITTED: class DebugHelper func draw_debug_helpers(_time_since_last_frame): for i in debug_helpers.size(): var _helper = debug_helpers[i] draw(_helper) _helper.age += _time_since_last_frame if _helper.age >= _helper.timeout: debug_helpers.remove(_helper) ``` This is essentially saying: "Are we there yet? Are we there yet? Are we there yet?". If the helper will be drawn for 179 frames and then time out on the 180th, that's 179 out of 180 pointless condition checks. It's usually better to use event- or signal-based logic, so this draw-manager object can simply be *told* when it's time to stop drawing a particular helper, or when a timer linked to that helper has timed out. Here's a version that doesn't busy-wait. ```gdscript OMITTED: class DebugHelper func begin_drawing_debug_helper(_helper_parameters, _time): var _new_helper = DebugHelper.new(_helper_parameters) debug_helpers.append(_new_helper) func iterate_debug_draws(_time_since_last_frame): for i in debug_helpers.size(): var _helper = debug_helpers[i] draw(_helper) func end_debug_draw(_helper): debug_helpers.remove(_helper) ``` Who tells this object to call `end_debug_draw()`, though? That depends on the toolbox you're working with. If you're using a game engine or a library with QoL classes, they'll typically have a timer-like class you can use that either: - ... busy-waits, but is in a way that's better-optimized than doing it yourself. Using a faster programming language at a lower level, for example. - ... puts an asynchronous thread to sleep and wakes it when time is up. (See [this StackOverflow post](https://softwareengineering.stackexchange.com/questions/328586/how-does-sleeping-a-thread-work) if you want some inspiration for doing it this way.) - ... a third option that is beyond my comprehension. But if you need to make one yourself, it's easy. Here's one in GDScript: ```python # Run `tick()` in the manner of your choice. class Timer extends Node: age = 0 time = 0 func _init(_time): time = _time func tick(_delta): age += _delta if age >= time: timeout.emit() signal timeout() ``` If busy-waiting is your only option, consider how often the check needs to be performed. For example: an AI in a video game doesn't necessarily need to check the player's position every frame - it may only need to update the position once a second, or once every five seconds. (Even real people can't make strategic decisions 60 times a second, after all.)