Tools for synchronizing threads using better locks and signals.
Project description
threadtools
Support for signals and better locks in native Python.
Inspiration
PyQt lets you "emit" signals that have function callbacks tied to them. Why shouldn't we have that in native Python?
Typical Usage
Signals
import time
from threading import Thread
from threadtools import Signal, process_events
class ThreadedProcess:
"""Mimics a long-running process that updates its progress."""
def __init__(self):
self.somethingHappened = Signal[str]()
self.countChanged = Signal[int]()
self.finished = Signal() # no typing implies no arguments to `emit()`
def run(self):
for i in range(1, 6):
time.sleep(1)
self.countChanged.emit(i)
if i == 3:
self.somethingHappened.emit("Something happened!")
self.finished.emit()
threaded_process = ThreadedProcess()
thread = Thread(target=threaded_process.run)
# connect signals
threaded_process.countChanged.connect(print)
threaded_process.somethingHappened.connect(print)
threaded_process.finished.connect(lambda: print("Done!"))
# run the thread
thread.start()
# you must call `process_events()` to receive signals from other threads
# `emit()` was called from a different thread than `connect()`, so the callbacks are queued
while thread.is_alive():
process_events()
# prints:
# 1
# 2
# 3
# Something happened!
# 4
# 5
# Done!
DataLock
from threading import Thread
from threadtools import DataLock
# DataLocks are generic; they support any type
LOCKED_INTEGER = DataLock(0)
LOCKED_STRING = DataLock("Hello, World!")
class DataAccessor:
"""Accesses and mutates data that is behind a lock."""
def __init__(self, int_value: int):
self.int_value = int_value
def run(self):
# using a context manager locks the lock and returns the stored data
with LOCKED_INTEGER as locked_int:
# reading data
print(locked_int)
# writing data
# BAD!!
# this does not change the value inside the lock
# (Python references don't work that way)
locked_int = self.int_value
# good
# DataLocks are reentrant; this will not cause a deadlock
LOCKED_INTEGER.set(self.int_value)
# you can also get the data inside the lock using `get()`
print(LOCKED_INTEGER.get())
# the lock is unlocked here, at the end of the context
first_accessor = DataAccessor(1)
first_thread = Thread(target=first_accessor.run)
second_accessor = DataAccessor(2)
second_thread = Thread(target=second_accessor.run)
first_thread.start()
second_thread.start()
first_thread.join()
second_thread.join()
# if `first_thread` is started first, prints:
# 0
# 1
# 1
# 2
Thread Safety
Signals are thread-safe as long as they are connected correctly. See the connect() method for more details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file threadtools-1.0.0.tar.gz.
File metadata
- Download URL: threadtools-1.0.0.tar.gz
- Upload date:
- Size: 19.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82bd950cbe46d2021cc7e96aeb29794560f23954b254105c5beefc8715025256
|
|
| MD5 |
0f299c7a5cdc2f023bb7f73c7ec43fce
|
|
| BLAKE2b-256 |
2fc746081f256c5876d4d2b63ebd06054472673f00a131f9cfdd3ca71f81f989
|
Provenance
The following attestation bundles were made for threadtools-1.0.0.tar.gz:
Publisher:
pypi.yml on drewlwhitney/threadtools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
threadtools-1.0.0.tar.gz -
Subject digest:
82bd950cbe46d2021cc7e96aeb29794560f23954b254105c5beefc8715025256 - Sigstore transparency entry: 234218426
- Sigstore integration time:
-
Permalink:
drewlwhitney/threadtools@d0659ffa1820c23f2591124d3f4aa9556f5de050 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/drewlwhitney
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@d0659ffa1820c23f2591124d3f4aa9556f5de050 -
Trigger Event:
release
-
Statement type:
File details
Details for the file threadtools-1.0.0-py3-none-any.whl.
File metadata
- Download URL: threadtools-1.0.0-py3-none-any.whl
- Upload date:
- Size: 19.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c73cae4b5eacb625919b7adaf397cdc5de2c3ea6d4f6ec134fa5a9dc5bf1968
|
|
| MD5 |
f08b9844aaa22490f5f3fb0672bf5e53
|
|
| BLAKE2b-256 |
52ce4f860b1bb4e7ad799cdbc3249a7b4da8a594c9ce47caa85e4f9017dfac26
|
Provenance
The following attestation bundles were made for threadtools-1.0.0-py3-none-any.whl:
Publisher:
pypi.yml on drewlwhitney/threadtools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
threadtools-1.0.0-py3-none-any.whl -
Subject digest:
9c73cae4b5eacb625919b7adaf397cdc5de2c3ea6d4f6ec134fa5a9dc5bf1968 - Sigstore transparency entry: 234218430
- Sigstore integration time:
-
Permalink:
drewlwhitney/threadtools@d0659ffa1820c23f2591124d3f4aa9556f5de050 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/drewlwhitney
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@d0659ffa1820c23f2591124d3f4aa9556f5de050 -
Trigger Event:
release
-
Statement type: