Threading#

The Scheduler is thread safe and supports parallel execution of pending Jobs. Jobs with a relevant execution time or blocking IO operations can delay each other.

Warning

When running Jobs in parallel, be sure that possible side effects of the scheduled functions are implemented in a thread safe manner.

The following examples show the difference between concurrent and parallel Schedulers:

Concurrent execution#

By default the Scheduler will execute its Jobs sequentially. The total duration when executing multiple Jobs will therefore be greater than the sum of the individual run times.

>>> import datetime as dt
>>> import time

>>> from scheduler import Scheduler

>>> def sleep(secs: float):
...     time.sleep(secs)
...

>>> schedule = Scheduler()
>>> job_1 = schedule.once(dt.timedelta(), sleep, kwargs={"secs": 0.1})
>>> job_2 = schedule.once(dt.timedelta(), sleep, kwargs={"secs": 0.1})

>>> start_time = time.perf_counter()
>>> n_exec = schedule.exec_jobs()
>>> total_seconds = time.perf_counter() - start_time
>>> n_exec
2

>>> 0.2 < total_seconds and total_seconds < 0.21
True

Parallel execution#

The number of worker threads for the Scheduler can be defined with the n_threads argument. For n_threads = 0 the Scheduler will spawn a seperate worker thread for every pending Job.

>>> import datetime as dt
>>> import time

>>> from scheduler import Scheduler

>>> def sleep(secs: float):
...     time.sleep(secs)
...

>>> schedule = Scheduler(n_threads=0)
>>> job_1 = schedule.once(dt.timedelta(), sleep, kwargs={"secs": 0.1})
>>> job_2 = schedule.once(dt.timedelta(), sleep, kwargs={"secs": 0.1})

>>> start_time = time.perf_counter()
>>> n_exec = schedule.exec_jobs()
>>> total_seconds = time.perf_counter() - start_time
>>> n_exec
2

>>> 0.1 < total_seconds and total_seconds < 0.11
True