Module pauser.

Pauser

The Pauser class provides a pause method that delays execution for a specified interval. When possible, it uses time.sleep() for the initial part of the delay, and then completes the delay by looping while checking the elapsed time using time.perf_counter_ns().

Example:

pause execution for 1.5 seconds

>>> from scottbrian_utils.pauser import Pauser
>>> import time
>>> pauser = Pauser()
>>> start_time = time.time()
>>> pauser.pause(1.5)
>>> stop_time = time.time()
>>> print(f'paused for {stop_time - start_time:.1f} seconds')
paused for 1.5 seconds

While time.sleep() is useful for a rough delay, at very small intervals it can delay for more time than requested. For example, time.sleep(0.001) might return after 0.015 seconds.

Pauser.pause() provides accuracy at the expense of looping for some portion of the delay, perhaps the entire delay when a small interval is requested. time.sleep() should be preferred for applications that do not require acccracy since it will give up the processor and allow other work to make progress.

The Pauser module contains:

  1. Pauser class with methods:

    1. calibrate

    2. get_metrics

    3. pause

class pauser.MetricResults(pause_ratio: float, sleep_ratio: float)

Results for get_metrics method.

Create new instance of MetricResults(pause_ratio, sleep_ratio)

pause_ratio: float

Alias for field number 0

sleep_ratio: float

Alias for field number 1

class pauser.Pauser(min_interval_secs=0.03, part_time_factor=0.4)

Pauser class to pause execution.

Initialize the instance.

The Pauser instance is initially created with the specified or defaulted values for min_interval_secs and part_time_factor. These values should be chosen based on the observed behavior of time.sleep() at low enough intervals to get an idea of where the sleep time fails to reflect the requested sleep time. Note that Pauser.calibrate() can be used to find and set the best value for min_interval_secs.

Parameters:
  • min_interval_secs (float) – the minimum interval that will use time.sleep() for a portion of the pause interval.

  • part_time_factor (float) – the value to multiply the sleep interval by to reduce the sleep time

Raises:
  • IncorrectInput – The min_interval_secs argument is not valid - it must be a positive non-zero float.

  • IncorrectInput – The part_time_factor argument is not valid - it must be a non-zero float no greater than 1.0.

Example: create an instance of Pauser with defaults

>>> from scottbrian_utils.pauser import Pauser
>>> pauser = Pauser()
>>> pauser
Pauser(min_interval_secs=0.03, part_time_factor=0.4)
calibrate(min_interval_msecs=1, max_interval_msecs=300, increment=5, part_time_factor=0.4, max_sleep_late_ratio=1.0, iterations=8)

Calibrate the Pauser for the current environment.

The calibrate method determines and sets the correct value for min_interval_secs, the lowest value for which the pause method will use time.sleep() to achieve a portion of the delay. This helps to ensure that time.sleep() is used for as much of the delay as possible to help free up the processor to perform other work. Note that setting the correct value for min_interval_secs helps ensure delay accuracy be preventing time.sleep() from being used at intervals that it is unable to accurately process.

Parameters:
  • min_interval_msecs (int) – starting interval of span to calibrate

  • max_interval_msecs (int) – ending interval of span to calibrate

  • increment (int) – number of milliseconds to skip for the next interval

  • part_time_factor (float) – factor of sleep time to try

  • max_sleep_late_ratio (float) – allowed error threshold

  • iterations (int) – number of iteration per interval

Raises:
  • IncorrectInput – The min_interval_msecs argument is not valid - it must be a positive non-zero integer.

  • IncorrectInput – The max_interval_msecs argument is not valid - it must be a positive non-zero integer equal to or greater than min_interval_msecs.

  • IncorrectInput – The increment argument is not valid - it must be a positive non-zero integer.

  • IncorrectInput – The part_time_factor argument is not valid - it must be a positive non-zero float no greater than 1.0.

  • IncorrectInput – The max_sleep_late_ratio argument is not valid - it must be a positive non-zero float no greater than 1.0.

  • IncorrectInput – The iterations argument is not valid - it must be a positive non-zero integer.

Example: calibrate the Pauser for a specific range of intervals

>>> from scottbrian_utils.pauser import Pauser
>>> pauser = Pauser(min_interval_secs=1.0)
>>> pauser.calibrate(min_interval_msecs=5,
...                  max_interval_msecs=100,
...                  increment=5)
:rtype: :sphinx_autodoc_typehints_type:`\:py\:obj\:\`None\``
>>> print(f'{pauser.min_interval_secs=}')
pauser.min_interval_secs=0.015
get_metrics(min_interval_msecs=1, max_interval_msecs=300, iterations=8)

Get the pauser metrics.

Parameters:
  • min_interval_msecs (int) – starting number of milliseconds for scan

  • max_interval_msecs (int) – ending number of milliseconds for scan

  • iterations (int) – number of iterations to run each interval

Return type:

MetricResults

Returns:

The pause interval ratio (actual/requested) is returned in Metrics.pause_ratio and is an indication of the accuarcy of the requested delay with the value 1 being perfect. The sleep ratio (sleep/requested) is returned in Metrics.sleep_ratio and is the portion of the delay accomplished using time.sleep().

Raises:
  • IncorrectInput – The min_interval_msecs argument is not valid - it must be a positive non-zero integer.

  • IncorrectInput – The max_interval_msecs argument is not valid - it must be a positive non-zero integer equal to or greater than min_interval_msecs.

  • IncorrectInput – The iterations argument is not valid - it must be a positive non-zero integer.

Example: get the metrics for a pause of 0.1 seconds.

Note that the accuracy is very good at 1.0 and the portion of the delay provided by time.sleep() is about 60%.

>>> from scottbrian_utils.pauser import Pauser
>>> pauser = Pauser()
>>> metrics = pauser.get_metrics(min_interval_msecs=100,
...                              max_interval_msecs=100,
...                              iterations=3)
>>> print(f'{metrics.pause_ratio=:.1f}, '
...       f'{metrics.sleep_ratio=:.1f}')
metrics.pause_ratio=1.0, metrics.sleep_ratio=0.6
Example: get the metrics for a pause range of 0.98 to 1.0

seconds. Note that the accuracy is very good at 1.0 but the portion of the delay provided by time.sleep() is zero. This is so because the Pauser was instantiated with a min_interval_secs of 1.0 which effectively prevents time.sleep() from being used for any requested delays af 1 second or less.

>>> from scottbrian_utils.pauser import Pauser
>>> pauser = Pauser(min_interval_secs=1.0)
>>> metrics = pauser.get_metrics(min_interval_msecs=980,
...                              max_interval_msecs=1000,
...                              iterations=3)
>>> print(f'{metrics.pause_ratio=:.1f}, '
...       f'{metrics.sleep_ratio=:.1f}')
metrics.pause_ratio=1.0, metrics.sleep_ratio=0.0
pause(interval)

Pause for the specified number of seconds.

Parameters:

interval (Union[int, float]) – number of seconds to pause

Raises:

IncorrectInput – The interval arg is not valid - please provide a non-negative value.

Return type:

None

Example: pause for 1 second

>>> from scottbrian_utils.pauser import Pauser
>>> pauser = Pauser()
>>> pauser.pause(1)

Example: pause for 1 half second and verify using time.time

>>> from scottbrian_utils.pauser import Pauser
>>> import time
>>> pauser = Pauser()
>>> start_time = time.time()
>>> pauser.pause(0.5)
>>> stop_time = time.time()
>>> interval = stop_time - start_time
>>> print(f'paused for {interval:.1f} seconds')
paused for 0.5 seconds
Example: pause for 1 quarter second and verify using

time.perf_counter_ns

>>> from scottbrian_utils.pauser import Pauser
>>> import time
>>> pauser = Pauser()
>>> start_time = time.perf_counter_ns()
>>> pauser.pause(0.25)
>>> stop_time = time.perf_counter_ns()
>>> interval = (stop_time - start_time) * Pauser.NS_2_SECS
>>> print(f'paused for {interval:.2f} seconds')
paused for 0.25 seconds