Last active
April 10, 2026 21:00
-
-
Save drscotthawley/44bae7d72c693fa725692bf18126d9e5 to your computer and use it in GitHub Desktop.
do_every: wallclock-based interval switch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Instead of having to figure out how many steps or how many epochs I want to wait, | |
| # (e.g. `if epochs % viz_every == 0:` or `if steps % ckpt_every == 0`) | |
| # sometimes I'd rather have something wall-clock-time-based and easy to call. | |
| # Hence this. | |
| # Sample usage: `if do_every('15min'):`, or with optional id: `if do_every('1h', 'viz'):` etc. | |
| import time | |
| import inspect | |
| import re | |
| _timers = {} | |
| def _parse_interval(s): | |
| """Parse a human-readable interval string or number into seconds.""" | |
| if isinstance(s, (int, float)): | |
| return float(s) | |
| s = str(s).strip().lower() | |
| units = {'s': 1, 'sec': 1, 'second': 1, 'seconds': 1, | |
| 'm': 60, 'min': 60, 'minute': 60, 'minutes': 60, | |
| 'h': 3600, 'hr': 3600, 'hour': 3600, 'hours': 3600} | |
| m = re.fullmatch(r'(\d+(?:\.\d+)?)\s*([a-z]+)', s) | |
| if m: | |
| val, unit = float(m.group(1)), m.group(2) | |
| if unit in units: | |
| return val * units[unit] | |
| raise ValueError(f"Can't parse interval: {s!r}") | |
| def do_every(interval, id=None, first_true=True): | |
| """Return True if at least `interval` time has passed since the last True at this call site. | |
| Sample usage: do_every('15min'), do_every('1h', 'viz') etc. | |
| If `id` is None, the call site is identified by filename and line number; otherwise, it's identified by filename and `id`. | |
| This allows you to have multiple independent timers in the same file. | |
| By default it will be true the first time it's called. Set first_true=False to change that. | |
| """ | |
| frame = inspect.stack()[1] | |
| key = f"{frame.filename}:{id}" if id is not None else f"{frame.filename}:{frame.lineno}" | |
| seconds = _parse_interval(interval) | |
| now = time.time() | |
| is_first = key not in _timers | |
| if now - _timers.get(key, 0) >= seconds: | |
| _timers[key] = now | |
| return first_true if is_first else True | |
| return False |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment