Name | threadlet JSON |
Version |
3.2.1
JSON |
| download |
home_page | None |
Summary | Convenient threading and improved ThreadPoolExecutor |
upload_time | 2024-06-29 09:03:15 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.7 |
license | None |
keywords |
thread pool
threads
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# threadlet
[![PyPI - Version](https://img.shields.io/pypi/v/threadlet.svg)](https://pypi.org/project/threadlet)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/threadlet.svg)](https://pypi.org/project/threadlet)
More convenient threads and pools with futures.
```python
from threadlet import spawn, go
def plus2(n):
return n + 2
# run function in thread
future = spawn(plus2, 1)
assert future.result() == 3
# run function in adaptive thread pool executor
future = go(plus2, 2)
assert future.result() == 4
```
* **spawn** is a helper which runs function in a separate thread and returns `Future`.
* **go** is a similar helper, but runs function in adaptive thread pool executor which is handled in background.
* **Task** is a wrapper for encapsulating a function, its arguments and `Future` object.
* **Worker** is a thread with a loop for executing incoming tasks.
* **SimpleThreadPoolExecutor** is a simple variant of `concurrent.futures.ThreadPoolExecutor` which spawns all the threads at the beginning.
* **ThreadPoolExecutor** is an adaptive variant of the `concurrent.futures.ThreadPoolExecutor` which automatically spawns and shutdowns threads depending on load.
One thread in the pool lives forever, new threads are spawned on `submit` call if there are no idle threads and die after some idle time(1 second by default).
-----
**Table of Contents**
- [Installation](#installation)
- [Usage](#usage)
- [Benchmarks](#benchmarks)
- [License](#license)
## Installation
```console
pip install threadlet
```
## Usage
```python
import threading
from threadlet import (
spawn,
go,
Future,
Task,
Worker,
SimpleThreadPoolExecutor,
ThreadPoolExecutor,
)
def calc(x):
return x * 2
# execute function in an adaptive thread pool executor
# which is going to be started automatically at first `go` call and shut down at application exit
future = go(calc, 2)
assert future.result() == 4
# is equivalent to:
with ThreadPoolExecutor() as tpe:
future = tpe.submit(calc, 2)
assert future.result() == 4
# execute function in a separate thread:
future = spawn(calc, 2)
assert future.result() == 4
# is equivalent to:
task = Task(Future(), calc, [2], {})
threading.Thread(target=task.run).start()
assert task.future.result() == 4
# spawns one thread(worker) to sequentially handle all submitted functions
with Worker() as w:
f1 = w.submit(calc, 3)
f2 = w.submit(calc, 4)
assert f1.result() == 6
assert f2.result() == 8
# spawns 4 threads(workers) to handle all tasks in parallel
with SimpleThreadPoolExecutor(4) as tpe:
future = tpe.submit(calc, 5)
assert future.result() == 10
```
## Benchmarks
* submit: submits 1 million futures.
* e2e[N] (end to end[N workers]): submits 1 million futures using N workers and consumes results in a separate thread.
```
concurrent.futures.thread.ThreadPoolExecutor submit: time=12.94s size=0.04mb, peak=43.61mb
threadlet.ThreadPoolExecutor submit: time= 2.89s size=0.04mb, peak=20.35mb
threadlet.SimpleThreadPoolExecutor submit: time= 2.72s size=0.04mb, peak=24.49mb
concurrent.futures.thread.ThreadPoolExecutor e2e[1]: time=15.80s size=0.04mb, peak=28.56mb
threadlet.ThreadPoolExecutor e2e[1]: time= 4.32s size=0.02mb, peak=19.48mb
threadlet.SimpleThreadPoolExecutor e2e[1]: time= 4.23s size=0.02mb, peak=26.45mb
concurrent.futures.thread.ThreadPoolExecutor e2e[2]: time=33.36s size=0.07mb, peak=32.00mb
threadlet.ThreadPoolExecutor e2e[2]: time= 4.35s size=0.02mb, peak=35.83mb
threadlet.SimpleThreadPoolExecutor e2e[2]: time= 4.18s size=0.02mb, peak=41.81mb
concurrent.futures.thread.ThreadPoolExecutor e2e[4]: time= 7.49s size=0.11mb, peak=42.97mb
threadlet.ThreadPoolExecutor e2e[4]: time= 4.37s size=0.03mb, peak=28.21mb
threadlet.SimpleThreadPoolExecutor e2e[4]: time= 4.30s size=0.02mb, peak=39.81mb
concurrent.futures.thread.ThreadPoolExecutor e2e[8]: time= 7.30s size=0.21mb, peak=41.04mb
threadlet.ThreadPoolExecutor e2e[8]: time= 4.49s size=0.05mb, peak=29.20mb
threadlet.SimpleThreadPoolExecutor e2e[8]: time= 4.18s size=0.03mb, peak=38.36mb
```
## License
`threadlet` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
Raw data
{
"_id": null,
"home_page": null,
"name": "threadlet",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "thread pool, threads",
"author": null,
"author_email": "Andrii Kuzmin <jack.cvr@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/11/87/b2415c4e1ac5a03021a7747eb8672db8cdbebfb19ae439210b7c464550ca/threadlet-3.2.1.tar.gz",
"platform": null,
"description": "# threadlet\n\n[![PyPI - Version](https://img.shields.io/pypi/v/threadlet.svg)](https://pypi.org/project/threadlet)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/threadlet.svg)](https://pypi.org/project/threadlet)\n\nMore convenient threads and pools with futures.\n\n```python\nfrom threadlet import spawn, go\n\n\ndef plus2(n):\n return n + 2\n\n\n# run function in thread\nfuture = spawn(plus2, 1)\nassert future.result() == 3\n\n# run function in adaptive thread pool executor\nfuture = go(plus2, 2)\nassert future.result() == 4\n```\n\n* **spawn** is a helper which runs function in a separate thread and returns `Future`.\n* **go** is a similar helper, but runs function in adaptive thread pool executor which is handled in background.\n* **Task** is a wrapper for encapsulating a function, its arguments and `Future` object.\n* **Worker** is a thread with a loop for executing incoming tasks.\n* **SimpleThreadPoolExecutor** is a simple variant of `concurrent.futures.ThreadPoolExecutor` which spawns all the threads at the beginning.\n* **ThreadPoolExecutor** is an adaptive variant of the `concurrent.futures.ThreadPoolExecutor` which automatically spawns and shutdowns threads depending on load.\nOne thread in the pool lives forever, new threads are spawned on `submit` call if there are no idle threads and die after some idle time(1 second by default).\n\n-----\n\n**Table of Contents**\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Benchmarks](#benchmarks)\n- [License](#license)\n\n## Installation\n\n```console\npip install threadlet\n```\n\n## Usage\n\n```python\nimport threading\nfrom threadlet import (\n spawn,\n go,\n Future,\n Task,\n Worker,\n SimpleThreadPoolExecutor,\n ThreadPoolExecutor,\n)\n\n\ndef calc(x):\n return x * 2\n\n\n# execute function in an adaptive thread pool executor\n# which is going to be started automatically at first `go` call and shut down at application exit\nfuture = go(calc, 2)\nassert future.result() == 4\n# is equivalent to:\nwith ThreadPoolExecutor() as tpe:\n future = tpe.submit(calc, 2)\n assert future.result() == 4\n\n# execute function in a separate thread:\nfuture = spawn(calc, 2)\nassert future.result() == 4\n# is equivalent to:\ntask = Task(Future(), calc, [2], {})\nthreading.Thread(target=task.run).start()\nassert task.future.result() == 4\n\n# spawns one thread(worker) to sequentially handle all submitted functions\nwith Worker() as w:\n f1 = w.submit(calc, 3)\n f2 = w.submit(calc, 4)\n assert f1.result() == 6\n assert f2.result() == 8\n\n# spawns 4 threads(workers) to handle all tasks in parallel\nwith SimpleThreadPoolExecutor(4) as tpe:\n future = tpe.submit(calc, 5)\n assert future.result() == 10\n```\n\n\n## Benchmarks\n\n* submit: submits 1 million futures.\n* e2e[N] (end to end[N workers]): submits 1 million futures using N workers and consumes results in a separate thread.\n\n```\nconcurrent.futures.thread.ThreadPoolExecutor submit: time=12.94s size=0.04mb, peak=43.61mb\n threadlet.ThreadPoolExecutor submit: time= 2.89s size=0.04mb, peak=20.35mb\n threadlet.SimpleThreadPoolExecutor submit: time= 2.72s size=0.04mb, peak=24.49mb\n\nconcurrent.futures.thread.ThreadPoolExecutor e2e[1]: time=15.80s size=0.04mb, peak=28.56mb\n threadlet.ThreadPoolExecutor e2e[1]: time= 4.32s size=0.02mb, peak=19.48mb\n threadlet.SimpleThreadPoolExecutor e2e[1]: time= 4.23s size=0.02mb, peak=26.45mb\n\nconcurrent.futures.thread.ThreadPoolExecutor e2e[2]: time=33.36s size=0.07mb, peak=32.00mb\n threadlet.ThreadPoolExecutor e2e[2]: time= 4.35s size=0.02mb, peak=35.83mb\n threadlet.SimpleThreadPoolExecutor e2e[2]: time= 4.18s size=0.02mb, peak=41.81mb\n\nconcurrent.futures.thread.ThreadPoolExecutor e2e[4]: time= 7.49s size=0.11mb, peak=42.97mb\n threadlet.ThreadPoolExecutor e2e[4]: time= 4.37s size=0.03mb, peak=28.21mb\n threadlet.SimpleThreadPoolExecutor e2e[4]: time= 4.30s size=0.02mb, peak=39.81mb\n\nconcurrent.futures.thread.ThreadPoolExecutor e2e[8]: time= 7.30s size=0.21mb, peak=41.04mb\n threadlet.ThreadPoolExecutor e2e[8]: time= 4.49s size=0.05mb, peak=29.20mb\n threadlet.SimpleThreadPoolExecutor e2e[8]: time= 4.18s size=0.03mb, peak=38.36mb\n```\n\n## License\n\n`threadlet` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.\n",
"bugtrack_url": null,
"license": null,
"summary": "Convenient threading and improved ThreadPoolExecutor",
"version": "3.2.1",
"project_urls": {
"Documentation": "https://github.com/jackcvr/threadlet#readme",
"Issues": "https://github.com/jackcvr/threadlet/issues",
"Source": "https://github.com/jackcvr/threadlet"
},
"split_keywords": [
"thread pool",
" threads"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "9b690f25e09d402bfb432574f1ace8c607032a9c35f01dc37823c6ef1a1702c1",
"md5": "442b8f3038487e7d230a155ebdd0b46b",
"sha256": "ede3bd855d215fefa4fac90b164439fcc40f699c614d50a26c5bd598ffdaaebc"
},
"downloads": -1,
"filename": "threadlet-3.2.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "442b8f3038487e7d230a155ebdd0b46b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 5630,
"upload_time": "2024-06-29T09:03:13",
"upload_time_iso_8601": "2024-06-29T09:03:13.711925Z",
"url": "https://files.pythonhosted.org/packages/9b/69/0f25e09d402bfb432574f1ace8c607032a9c35f01dc37823c6ef1a1702c1/threadlet-3.2.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "1187b2415c4e1ac5a03021a7747eb8672db8cdbebfb19ae439210b7c464550ca",
"md5": "d0fc02b896da3ad89ee1f0e963fe9e33",
"sha256": "d40b4b6b3a6cf10b78c19a54d25e47ad3f7425ed2adc14593d98d0fd4834be56"
},
"downloads": -1,
"filename": "threadlet-3.2.1.tar.gz",
"has_sig": false,
"md5_digest": "d0fc02b896da3ad89ee1f0e963fe9e33",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 8728,
"upload_time": "2024-06-29T09:03:15",
"upload_time_iso_8601": "2024-06-29T09:03:15.505505Z",
"url": "https://files.pythonhosted.org/packages/11/87/b2415c4e1ac5a03021a7747eb8672db8cdbebfb19ae439210b7c464550ca/threadlet-3.2.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-06-29 09:03:15",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "jackcvr",
"github_project": "threadlet#readme",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "threadlet"
}