Install & Compatibility
Where this runs
tested against v1.0.2 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.920 runs
installs and imports cleanly · install 0.0s · import 0.000s · 22.6MB
glibcpy 3.10–3.920 runs
installs and imports cleanly · install 2.8s · import 0.000s · 23MB
21MB installed
● package 21MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
ThreadLoop
✓ from threadloop import ThreadLoop
✗ from threadloop import ThreadLoopExecutor
This quickstart demonstrates how to initialize `ThreadLoopExecutor` as a context manager and submit both Tornado coroutines and regular synchronous functions. The `submit` method returns a future, and `.result()` can be called to block until the task completes and retrieve its return value. Note that `tornado.gen.coroutine` is used for demonstration, which is an older decorator; modern Tornado often uses `async def` functions.
import tornado.gen
from threadloop import ThreadLoopExecutor
@tornado.gen.coroutine
def my_coroutine(name):
print(f"Hello from {name} in coroutine!")
yield tornado.gen.sleep(0.1) # Simulate async work
print(f"Goodbye from {name}!")
return f"Result from {name}"
def sync_function(x, y):
print(f"Running sync_function with {x} and {y}")
return x + y
if __name__ == '__main__':
# Example 1: Running a Tornado coroutine in the ThreadLoopExecutor
with ThreadLoopExecutor() as executor:
future_coro = executor.submit(my_coroutine, "CoroutineWorker")
result_coro = future_coro.result() # Blocks until coroutine completes
print(f"Coroutine result: {result_coro}")
# Example 2: Running a regular synchronous function
with ThreadLoopExecutor() as executor:
future_sync = executor.submit(sync_function, 10, 20)
result_sync = future_sync.result()
print(f"Sync function result: {result_sync}")
Debug
Known issues
breakingThe `threadloop` library has not been updated since 2016 (version 1.0.2) and may have compatibility issues with newer Python (3.6+) and Tornado versions. Newer Python versions, especially 3.13+, introduce significant changes to threading (e.g., free-threaded CPython without GIL by default), which might affect `threadloop`'s behavior or performance.fixThoroughly test `threadloop` with your specific Python and Tornado versions. Consider modern alternatives like `concurrent.futures.ThreadPoolExecutor` for general threading or `asyncio` with `loop.run_in_executor` for integrating blocking calls into an event loop for new projects.
affects: <=1.0.2
gotchaTasks submitted to `ThreadLoopExecutor` (or any `concurrent.futures.ThreadPoolExecutor`) can fail silently if their `Future` objects are not inspected (e.g., by calling `.result()`, `.exception()`, or attaching `add_done_callback`). Exceptions raised within submitted tasks will not propagate to the main thread unless explicitly retrieved.fixAlways retrieve the result or check for exceptions on `Future` objects returned by `submit()` or `map()`. For example, `future.result()` will re-raise any exception that occurred in the worker thread. Alternatively, use `future.add_done_callback(error_handler)` to process results or errors asynchronously.
affects: All
gotchaPython's Global Interpreter Lock (GIL) means that CPU-bound tasks executed within `ThreadLoopExecutor` (which uses threads) will not achieve true parallel execution across multiple CPU cores in standard CPython interpreters (pre-3.13 free-threaded builds). Threads are best for I/O-bound tasks where the GIL is released during blocking operations.fixFor CPU-bound parallelism, use `multiprocessing.Pool` or `concurrent.futures.ProcessPoolExecutor` which utilize separate processes, bypassing the GIL. For I/O-bound tasks, threading is generally effective. Be aware that Python 3.13+ with free-threaded builds can offer true parallelism for CPU-bound threaded code.
affects: All (pre-Python 3.13 free-threaded builds)
gotchaAttempting to submit tasks to a `ThreadLoopExecutor` after it has been shut down will result in a `RuntimeError` or similar exception. This can happen if the executor's lifecycle is not managed correctly, especially when not using it as a context manager.fixAlways use `ThreadLoopExecutor` as a context manager (`with ThreadLoopExecutor() as executor:`) to ensure proper shutdown and resource management. If manually managing, ensure `executor.shutdown()` is called only after all tasks have been submitted and you are ready to terminate the pool.
affects: All
Upgrade
Version history
1.0.2latest on PyPI · released Apr 1, 2016
Audit
Dependencies
tornadorequiredCore functionality relies on Tornado's IOLoop for managing asynchronous operations. Specifically, `tornado>=4.0.0` is required.