async-batcher 0.2.0__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. async_batcher-0.2.2/PKG-INFO +183 -0
  2. async_batcher-0.2.2/README.md +151 -0
  3. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/batcher.py +9 -9
  4. {async_batcher-0.2.0 → async_batcher-0.2.2}/pyproject.toml +3 -3
  5. async_batcher-0.2.0/PKG-INFO +0 -101
  6. async_batcher-0.2.0/README.md +0 -68
  7. {async_batcher-0.2.0 → async_batcher-0.2.2}/LICENSE +0 -0
  8. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/__init__.py +0 -0
  9. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/aws/__init__.py +0 -0
  10. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/aws/dynamodb/__init__.py +0 -0
  11. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/aws/dynamodb/get.py +0 -0
  12. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/aws/dynamodb/write.py +0 -0
  13. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/exceptions.py +0 -0
  14. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/ml/__init__.py +0 -0
  15. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/ml/keras/__init__.py +0 -0
  16. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/ml/keras/model.py +0 -0
  17. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/ml/sklearn/__init__.py +0 -0
  18. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/ml/sklearn/model.py +0 -0
  19. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/scylladb/__init__.py +0 -0
  20. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/scylladb/update.py +0 -0
  21. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/sqlalchemy/__init__.py +0 -0
  22. {async_batcher-0.2.0 → async_batcher-0.2.2}/async_batcher/sqlalchemy/write.py +0 -0
@@ -0,0 +1,183 @@
1
+ Metadata-Version: 2.3
2
+ Name: async-batcher
3
+ Version: 0.2.2
4
+ Summary: A service to batch your http requests.
5
+ License: Apache-2.0
6
+ Keywords: python,asyncio,rest,grpc,fastapi
7
+ Author: Hussein Awala
8
+ Author-email: hussein@awala.fr
9
+ Requires-Python: >=3.10,<4.0
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Provides-Extra: aws
17
+ Provides-Extra: keras
18
+ Provides-Extra: scylla
19
+ Provides-Extra: sklearn
20
+ Provides-Extra: sqlalchemy
21
+ Requires-Dist: aioboto3 (>=13.1,<14.0) ; extra == "aws"
22
+ Requires-Dist: keras (>=2.12,<3.0) ; (python_version < "3.12") and (extra == "keras")
23
+ Requires-Dist: keras (>=2.12,<4) ; (python_version == "3.12") and (extra == "keras")
24
+ Requires-Dist: scikit-learn (>=1.2,<2.0) ; (python_version < "3.12") and (extra == "sklearn")
25
+ Requires-Dist: scikit-learn (>=1.3,<2.0) ; (python_version == "3.12") and (extra == "sklearn")
26
+ Requires-Dist: scylla-driver (>=3,<4) ; extra == "scylla"
27
+ Requires-Dist: sqlalchemy[asyncio] (>=1.4,<3) ; extra == "sqlalchemy"
28
+ Project-URL: Bug Tracker, https://github.com/hussein-awala/async-batcher/issues
29
+ Project-URL: Documentation, https://github.com/hussein-awala/async-batcher/blob/main/README.md
30
+ Project-URL: Repository, https://github.com/hussein-awala/async-batcher
31
+ Description-Content-Type: text/markdown
32
+
33
+ # AsyncBatcher - Asynchronous Batching for Python
34
+
35
+ ## Overview
36
+ AsyncBatcher is a generic, asynchronous batch processor for Python that efficiently groups incoming items into batches
37
+ and processes them asynchronously. It is designed for scenarios where multiple requests or tasks need to be handled in
38
+ batches to improve efficiency and throughput.
39
+
40
+ ## Key Features
41
+ - Asynchronous processing: Uses asyncio for non-blocking execution.
42
+ - Batching mechanism: Groups items into batches based on size or time constraints.
43
+ - Concurrency control: Limits the number of concurrent batch executions.
44
+ - Custom processing logic: Users must implement the `process_batch` method to define batch behavior.
45
+ - Queue management: Uses an `asyncio.Queue` to manage incoming items.
46
+ - Error handling: Ensures robust error reporting and handling.
47
+
48
+ ## How it works
49
+
50
+ ### 1. Receiving Items for Processing
51
+ - Users call `process(item)`, which adds the item to an internal queue.
52
+ - A `Future` object is returned immediately and the result is awaited asynchronously.
53
+
54
+ ### 2. Queue Management and Batching
55
+ - A background task (`run()`) continuously monitors the queue.
56
+ - Items are collected into batches based on:
57
+ - `max_batch_size`: Maximum items per batch.
58
+ - `max_queue_time`: Maximum time an item can wait before being processed.
59
+ - Once a batch is ready, it is passed to the processing function.
60
+
61
+ ### 3. Processing the Batch
62
+ - If `process_batch` is asynchronous, it is awaited directly.
63
+ - If `process_batch` is synchronous, it runs inside an `Executor`.
64
+ - Each item’s future is resolved with the corresponding processed result.
65
+
66
+ ### 4. Concurrency Control
67
+ - If `concurrency > 0`, a semaphore ensures that only a limited number of batches are processed simultaneously.
68
+ - Otherwise, all batches run concurrently.
69
+
70
+ ### 5. Stopping the Batcher
71
+ - Calling `stop(force=True)` cancels all ongoing tasks.
72
+ - Calling `stop(force=False)` waits for pending items to be processed before shutting down.
73
+
74
+ ```mermaid
75
+ sequenceDiagram
76
+ participant User
77
+ participant AsyncBatcher
78
+ participant Queue as asyncio.Queue
79
+ participant RunLoop
80
+ participant Semaphore
81
+ participant BatchProcessor
82
+
83
+ User->>AsyncBatcher: process(item)
84
+ activate AsyncBatcher
85
+ AsyncBatcher->>Queue: put(QueueItem(item, future))
86
+ AsyncBatcher-->>User: returns future
87
+ deactivate AsyncBatcher
88
+
89
+ Note over AsyncBatcher: Starts RunLoop on first process()
90
+
91
+ loop Run Loop (run() method)
92
+ RunLoop->>Queue: Collect items (max_batch_size/max_queue_time)
93
+ activate Queue
94
+ Queue-->>RunLoop: Batch [QueueItem1, QueueItem2...]
95
+ deactivate Queue
96
+
97
+ alt Concurrency Limited (concurrency > 0)
98
+ RunLoop->>Semaphore: acquire()
99
+ activate Semaphore
100
+ Semaphore-->>RunLoop: acquired
101
+ deactivate Semaphore
102
+ end
103
+
104
+ RunLoop->>BatchProcessor: create_task(_batch_run(batch))
105
+ activate BatchProcessor
106
+
107
+ alt Async process_batch
108
+ BatchProcessor->>AsyncBatcher: await process_batch(batch)
109
+ else Sync process_batch
110
+ BatchProcessor->>Executor: run_in_executor(process_batch)
111
+ end
112
+
113
+ AsyncBatcher-->>BatchProcessor: results [S1, S2...]
114
+ BatchProcessor->>QueueItem1.future: set_result(S1)
115
+ BatchProcessor->>QueueItem2.future: set_result(S2)
116
+ deactivate BatchProcessor
117
+
118
+ alt Concurrency Limited
119
+ RunLoop->>Semaphore: release()
120
+ end
121
+ end
122
+
123
+ Note over User, BatchProcessor: User's await future gets resolved
124
+ ```
125
+
126
+ ## How to use
127
+
128
+ To use the library, you need to install the package in your environment. You can install the package using pip:
129
+
130
+ ```bash
131
+ pip install async-batcher
132
+ ```
133
+
134
+ Then, you can create a new `AsyncBatcher` class by implementing the `process_batch` method:
135
+
136
+ ```python
137
+ import asyncio
138
+ import logging
139
+
140
+ from async_batcher.batcher import AsyncBatcher
141
+
142
+ class MyBatchProcessor(AsyncBatcher[int, int]):
143
+ async def process_batch(self, batch: list[int]) -> list[int]:
144
+ await asyncio.sleep(1) # Simulate processing delay
145
+ return [x * 2 for x in batch] # Example: Doubling each item
146
+
147
+ async def main():
148
+ batcher = MyBatchProcessor(max_batch_size=5, max_queue_time=2.0, concurrency=2)
149
+ results = await asyncio.gather(*[batcher.process(i) for i in range(10)])
150
+ print(results) # Output: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
151
+ await batcher.stop()
152
+
153
+ # Set logging level to DEBUG if you want to see more details and understand the flow
154
+ logging.basicConfig(level=logging.DEBUG)
155
+ asyncio.run(main())
156
+ ```
157
+
158
+ ## Benchmark
159
+
160
+ The benchmark is available in the [BENCHMARK.md](https://github.com/hussein-awala/async-batcher/blob/main/BENCHMARK.md)
161
+ file.
162
+
163
+ ## When to Use AsyncBatcher?
164
+ The AsyncBatcher library is ideal for applications that need to efficiently handle asynchronous requests in batches,
165
+ such as:
166
+
167
+ ### Machine Learning Model Serving
168
+ - Batch-processing requests to optimize inference performance (e.g., TensorFlow, PyTorch, Scikit-learn).
169
+
170
+ ### Database Bulk Operations
171
+ - Inserting multiple records in a single query to improve I/O efficiency and reduce costs (e.g., PostgreSQL, MySQL,
172
+ AWS DynamoDB).
173
+
174
+ ### Messaging and Network Optimization
175
+ - Sending multiple messages in a single API call to reduce latency and costs (e.g., Kafka, RabbitMQ, AWS SQS, AWS SNS).
176
+
177
+ ### Rate-Limited API Calls
178
+ - Aggregating requests to comply with API rate limits (e.g., GitHub API, Twitter API, OpenAI API).
179
+
180
+ ## Final Notes
181
+ - Implement `process_batch` according to your needs.
182
+ - Ensure `max_batch_size` and `max_queue_time` are configured based on performance requirements.
183
+ - Handle exceptions inside `process_batch` to avoid failures affecting other tasks.
@@ -0,0 +1,151 @@
1
+ # AsyncBatcher - Asynchronous Batching for Python
2
+
3
+ ## Overview
4
+ AsyncBatcher is a generic, asynchronous batch processor for Python that efficiently groups incoming items into batches
5
+ and processes them asynchronously. It is designed for scenarios where multiple requests or tasks need to be handled in
6
+ batches to improve efficiency and throughput.
7
+
8
+ ## Key Features
9
+ - Asynchronous processing: Uses asyncio for non-blocking execution.
10
+ - Batching mechanism: Groups items into batches based on size or time constraints.
11
+ - Concurrency control: Limits the number of concurrent batch executions.
12
+ - Custom processing logic: Users must implement the `process_batch` method to define batch behavior.
13
+ - Queue management: Uses an `asyncio.Queue` to manage incoming items.
14
+ - Error handling: Ensures robust error reporting and handling.
15
+
16
+ ## How it works
17
+
18
+ ### 1. Receiving Items for Processing
19
+ - Users call `process(item)`, which adds the item to an internal queue.
20
+ - A `Future` object is returned immediately and the result is awaited asynchronously.
21
+
22
+ ### 2. Queue Management and Batching
23
+ - A background task (`run()`) continuously monitors the queue.
24
+ - Items are collected into batches based on:
25
+ - `max_batch_size`: Maximum items per batch.
26
+ - `max_queue_time`: Maximum time an item can wait before being processed.
27
+ - Once a batch is ready, it is passed to the processing function.
28
+
29
+ ### 3. Processing the Batch
30
+ - If `process_batch` is asynchronous, it is awaited directly.
31
+ - If `process_batch` is synchronous, it runs inside an `Executor`.
32
+ - Each item’s future is resolved with the corresponding processed result.
33
+
34
+ ### 4. Concurrency Control
35
+ - If `concurrency > 0`, a semaphore ensures that only a limited number of batches are processed simultaneously.
36
+ - Otherwise, all batches run concurrently.
37
+
38
+ ### 5. Stopping the Batcher
39
+ - Calling `stop(force=True)` cancels all ongoing tasks.
40
+ - Calling `stop(force=False)` waits for pending items to be processed before shutting down.
41
+
42
+ ```mermaid
43
+ sequenceDiagram
44
+ participant User
45
+ participant AsyncBatcher
46
+ participant Queue as asyncio.Queue
47
+ participant RunLoop
48
+ participant Semaphore
49
+ participant BatchProcessor
50
+
51
+ User->>AsyncBatcher: process(item)
52
+ activate AsyncBatcher
53
+ AsyncBatcher->>Queue: put(QueueItem(item, future))
54
+ AsyncBatcher-->>User: returns future
55
+ deactivate AsyncBatcher
56
+
57
+ Note over AsyncBatcher: Starts RunLoop on first process()
58
+
59
+ loop Run Loop (run() method)
60
+ RunLoop->>Queue: Collect items (max_batch_size/max_queue_time)
61
+ activate Queue
62
+ Queue-->>RunLoop: Batch [QueueItem1, QueueItem2...]
63
+ deactivate Queue
64
+
65
+ alt Concurrency Limited (concurrency > 0)
66
+ RunLoop->>Semaphore: acquire()
67
+ activate Semaphore
68
+ Semaphore-->>RunLoop: acquired
69
+ deactivate Semaphore
70
+ end
71
+
72
+ RunLoop->>BatchProcessor: create_task(_batch_run(batch))
73
+ activate BatchProcessor
74
+
75
+ alt Async process_batch
76
+ BatchProcessor->>AsyncBatcher: await process_batch(batch)
77
+ else Sync process_batch
78
+ BatchProcessor->>Executor: run_in_executor(process_batch)
79
+ end
80
+
81
+ AsyncBatcher-->>BatchProcessor: results [S1, S2...]
82
+ BatchProcessor->>QueueItem1.future: set_result(S1)
83
+ BatchProcessor->>QueueItem2.future: set_result(S2)
84
+ deactivate BatchProcessor
85
+
86
+ alt Concurrency Limited
87
+ RunLoop->>Semaphore: release()
88
+ end
89
+ end
90
+
91
+ Note over User, BatchProcessor: User's await future gets resolved
92
+ ```
93
+
94
+ ## How to use
95
+
96
+ To use the library, you need to install the package in your environment. You can install the package using pip:
97
+
98
+ ```bash
99
+ pip install async-batcher
100
+ ```
101
+
102
+ Then, you can create a new `AsyncBatcher` class by implementing the `process_batch` method:
103
+
104
+ ```python
105
+ import asyncio
106
+ import logging
107
+
108
+ from async_batcher.batcher import AsyncBatcher
109
+
110
+ class MyBatchProcessor(AsyncBatcher[int, int]):
111
+ async def process_batch(self, batch: list[int]) -> list[int]:
112
+ await asyncio.sleep(1) # Simulate processing delay
113
+ return [x * 2 for x in batch] # Example: Doubling each item
114
+
115
+ async def main():
116
+ batcher = MyBatchProcessor(max_batch_size=5, max_queue_time=2.0, concurrency=2)
117
+ results = await asyncio.gather(*[batcher.process(i) for i in range(10)])
118
+ print(results) # Output: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
119
+ await batcher.stop()
120
+
121
+ # Set logging level to DEBUG if you want to see more details and understand the flow
122
+ logging.basicConfig(level=logging.DEBUG)
123
+ asyncio.run(main())
124
+ ```
125
+
126
+ ## Benchmark
127
+
128
+ The benchmark is available in the [BENCHMARK.md](https://github.com/hussein-awala/async-batcher/blob/main/BENCHMARK.md)
129
+ file.
130
+
131
+ ## When to Use AsyncBatcher?
132
+ The AsyncBatcher library is ideal for applications that need to efficiently handle asynchronous requests in batches,
133
+ such as:
134
+
135
+ ### Machine Learning Model Serving
136
+ - Batch-processing requests to optimize inference performance (e.g., TensorFlow, PyTorch, Scikit-learn).
137
+
138
+ ### Database Bulk Operations
139
+ - Inserting multiple records in a single query to improve I/O efficiency and reduce costs (e.g., PostgreSQL, MySQL,
140
+ AWS DynamoDB).
141
+
142
+ ### Messaging and Network Optimization
143
+ - Sending multiple messages in a single API call to reduce latency and costs (e.g., Kafka, RabbitMQ, AWS SQS, AWS SNS).
144
+
145
+ ### Rate-Limited API Calls
146
+ - Aggregating requests to comply with API rate limits (e.g., GitHub API, Twitter API, OpenAI API).
147
+
148
+ ## Final Notes
149
+ - Implement `process_batch` according to your needs.
150
+ - Ensure `max_batch_size` and `max_queue_time` are configured based on performance requirements.
151
+ - Handle exceptions inside `process_batch` to avoid failures affecting other tasks.
@@ -80,8 +80,8 @@ class AsyncBatcher(Generic[T, S], abc.ABC):
80
80
  self._current_task: asyncio.Task | None = None
81
81
  self._running_batches: dict[int, asyncio.Task] = {}
82
82
  self._concurrency_semaphore = asyncio.Semaphore(concurrency) if concurrency > 0 else None
83
- self._stop = False
84
- self._is_running = False
83
+ self._stop = asyncio.Event()
84
+ self._is_running = asyncio.Event()
85
85
 
86
86
  @abc.abstractmethod
87
87
  async def process_batch(self, batch: list[T]) -> list[S] | None:
@@ -99,7 +99,7 @@ class AsyncBatcher(Generic[T, S], abc.ABC):
99
99
  Returns:
100
100
  S: The result of processing the item.
101
101
  """
102
- if self._stop:
102
+ if self._stop.is_set():
103
103
  raise RuntimeError("Batcher is stopped")
104
104
  if self._current_task is None:
105
105
  self._current_task = asyncio.get_running_loop().create_task(self.run())
@@ -118,7 +118,7 @@ class AsyncBatcher(Generic[T, S], abc.ABC):
118
118
  return []
119
119
  if started_at is None:
120
120
  started_at = asyncio.get_event_loop().time()
121
- while 1:
121
+ while True:
122
122
  try:
123
123
  max_wait = self.max_queue_time - (asyncio.get_running_loop().time() - started_at)
124
124
  if max_wait > 0:
@@ -166,7 +166,7 @@ class AsyncBatcher(Generic[T, S], abc.ABC):
166
166
 
167
167
  async def run(self):
168
168
  """Run the batcher asynchronously."""
169
- self._is_running = True
169
+ self._is_running.set()
170
170
  task_id = 0
171
171
  if self.concurrency > 0:
172
172
  started_at = None
@@ -204,10 +204,10 @@ class AsyncBatcher(Generic[T, S], abc.ABC):
204
204
  self._batch_run(task_id, batch)
205
205
  )
206
206
  task_id += 1
207
- self._is_running = False
207
+ self._is_running.clear()
208
208
 
209
209
  def _should_stop(self):
210
- return self._stop and self._queue.qsize() == 0
210
+ return self._stop.is_set() and self._queue.qsize() == 0
211
211
 
212
212
  async def is_running(self):
213
213
  """Check if the batcher is running.
@@ -215,7 +215,7 @@ class AsyncBatcher(Generic[T, S], abc.ABC):
215
215
  Returns:
216
216
  bool: True if the batcher is running, False otherwise.
217
217
  """
218
- return self._is_running
218
+ return self._is_running.is_set()
219
219
 
220
220
  async def stop(self, force: bool = False, timeout: float | None = None):
221
221
  """Stop the batcher asyncio task.
@@ -234,7 +234,7 @@ class AsyncBatcher(Generic[T, S], abc.ABC):
234
234
  if not task.done():
235
235
  task.cancel()
236
236
  else:
237
- self._stop = True
237
+ self._stop.set()
238
238
  if (
239
239
  self._current_task
240
240
  and not self._current_task.done()
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "async-batcher"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  description = "A service to batch your http requests."
5
5
  authors = ["Hussein Awala <hussein@awala.fr>"]
6
6
  readme = "README.md"
@@ -15,7 +15,7 @@ packages = [{include = "async_batcher"}]
15
15
 
16
16
  [tool.poetry.dependencies]
17
17
  python = "^3.10"
18
- aioboto3 = {version = "^12.3", optional = true}
18
+ aioboto3 = {version = "^13.1", optional = true}
19
19
  scylla-driver = {version = "^3", optional = true}
20
20
  keras = [
21
21
  {version = "^2.12", optional = true, markers = "python_version < '3.12'"},
@@ -39,7 +39,7 @@ mock = "^5.1.0"
39
39
  pytest = "^8"
40
40
  pytest-asyncio = "^0.23.5"
41
41
  pre-commit = "^3"
42
- types-aioboto3 = {version = "^12.3", extras = ["dynamodb"]}
42
+ types-aioboto3 = {version = "^13.1", extras = ["dynamodb"]}
43
43
  aiosqlite = "^0.20"
44
44
  asyncpg = "^0.29"
45
45
 
@@ -1,101 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: async-batcher
3
- Version: 0.2.0
4
- Summary: A service to batch your http requests.
5
- Home-page: https://github.com/hussein-awala/async-batcher
6
- License: Apache-2.0
7
- Keywords: python,asyncio,rest,grpc,fastapi
8
- Author: Hussein Awala
9
- Author-email: hussein@awala.fr
10
- Requires-Python: >=3.10,<4.0
11
- Classifier: License :: OSI Approved :: Apache Software License
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Provides-Extra: aws
17
- Provides-Extra: keras
18
- Provides-Extra: scylla
19
- Provides-Extra: sklearn
20
- Provides-Extra: sqlalchemy
21
- Requires-Dist: aioboto3 (>=12.3,<13.0) ; extra == "aws"
22
- Requires-Dist: keras (>=2.12,<3.0) ; (python_version < "3.12") and (extra == "keras")
23
- Requires-Dist: keras (>=2.12,<4) ; (python_version == "3.12") and (extra == "keras")
24
- Requires-Dist: scikit-learn (>=1.2,<2.0) ; (python_version < "3.12") and (extra == "sklearn")
25
- Requires-Dist: scikit-learn (>=1.3,<2.0) ; (python_version == "3.12") and (extra == "sklearn")
26
- Requires-Dist: scylla-driver (>=3,<4) ; extra == "scylla"
27
- Requires-Dist: sqlalchemy[asyncio] (>=1.4,<3) ; extra == "sqlalchemy"
28
- Project-URL: Bug Tracker, https://github.com/hussein-awala/async-batcher/issues
29
- Project-URL: Documentation, https://github.com/hussein-awala/async-batcher/blob/main/README.md
30
- Project-URL: Repository, https://github.com/hussein-awala/async-batcher
31
- Description-Content-Type: text/markdown
32
-
33
- # Async Batcher
34
-
35
- This project provides a Python library to batch the asynchronous requests and handle them in batches.
36
-
37
- ## How to use
38
-
39
- To use the library, you need to install the package in your environment. You can install the package using pip:
40
-
41
- ```bash
42
- pip install async-batcher
43
- ```
44
-
45
- Then, you can create a new `AsyncBatcher` class by implementing the `process_batch` method:
46
-
47
- ```python
48
- from async_batcher.batcher import AsyncBatcher
49
-
50
- class MyAsyncBatcher(AsyncBatcher):
51
- async def process_batch(self, batch):
52
- # Process the batch
53
- print(batch)
54
-
55
- # Create a new instance of the `MyAsyncBatcher` class
56
- async_batcher = MyAsyncBatcher(max_batch_size=20)
57
- async_batcher.start()
58
- ```
59
-
60
- ## Benchmark
61
-
62
- To evaluate the performance of the `AsyncBatcher` library, we used the [Keras example](examples/keras)
63
- with [locust](https://locust.io/) to simulate multiple users making requests to the server.
64
-
65
- In this example, we have a tensorflow model that takes ~11ms to make a single prediction and ~13ms to process
66
- a batch of 200 predictions.
67
-
68
- For this benchmark, we ran the FastAPI server with Uvicorn with 12 workers,
69
- on a MacBook Pro with Apple M2 Max chip (12 cores).
70
-
71
- Predict endpoint:
72
-
73
- ![predict__total_requests_per_second.png](assets%2Fpredict__total_requests_per_second.png)
74
-
75
- Optimized Predict endpoint:
76
-
77
- ![optimized_predict__total_requests_per_second.png](assets%2Foptimized_predict__total_requests_per_second.png)
78
-
79
- As we can see from the graphs, for the `/predict` endpoint, the failure rate started to increase linearly at the RPS
80
- of ~284 requests/second, and the 95th percentile response time was ~1100ms at this point. Then with the increase of
81
- the RPS, the number of successful requests was ~130 requests/second in average, with a high failure rate
82
- (~300 from ~400 requests/second).
83
-
84
- For the `/optimized_predict` endpoint, the failure was smaller than 3 requests/second (0.00625%) during the whole test,
85
- the average response time was increasing slightly with the increase of the RPS, and it reached ~120ms in average at
86
- the end of the test (> 480 requests/second), with a 95th percentile response time almost stable and smaller than 500ms.
87
-
88
- You can find check the reports for more details:
89
- - [predict__report.html](assets/predict__report.html)
90
- - [optimized_predict__report.html](assets/optimized_predict__report.html)
91
- ## Use cases
92
-
93
- The `AsyncBatcher` library can be used in any application that needs to handle asynchronous requests in batches,
94
- such as:
95
- - Serving machine learning models that optimize the batch processing (e.g. TensorFlow, PyTorch, Scikit-learn, etc.)
96
- - Storing multiple records in a database in a single query to optimize the I/O operations (or to reduce the cost of the
97
- database operations, e.g. AWS DynamoDB)
98
- - Sending multiple messages in a single request to optimize the network operations (or to reduce the cost of the network
99
- operations, e.g. Kafka, RabbitMQ, AWS SQS, AWS SNS, etc.)
100
-
101
-
@@ -1,68 +0,0 @@
1
- # Async Batcher
2
-
3
- This project provides a Python library to batch the asynchronous requests and handle them in batches.
4
-
5
- ## How to use
6
-
7
- To use the library, you need to install the package in your environment. You can install the package using pip:
8
-
9
- ```bash
10
- pip install async-batcher
11
- ```
12
-
13
- Then, you can create a new `AsyncBatcher` class by implementing the `process_batch` method:
14
-
15
- ```python
16
- from async_batcher.batcher import AsyncBatcher
17
-
18
- class MyAsyncBatcher(AsyncBatcher):
19
- async def process_batch(self, batch):
20
- # Process the batch
21
- print(batch)
22
-
23
- # Create a new instance of the `MyAsyncBatcher` class
24
- async_batcher = MyAsyncBatcher(max_batch_size=20)
25
- async_batcher.start()
26
- ```
27
-
28
- ## Benchmark
29
-
30
- To evaluate the performance of the `AsyncBatcher` library, we used the [Keras example](examples/keras)
31
- with [locust](https://locust.io/) to simulate multiple users making requests to the server.
32
-
33
- In this example, we have a tensorflow model that takes ~11ms to make a single prediction and ~13ms to process
34
- a batch of 200 predictions.
35
-
36
- For this benchmark, we ran the FastAPI server with Uvicorn with 12 workers,
37
- on a MacBook Pro with Apple M2 Max chip (12 cores).
38
-
39
- Predict endpoint:
40
-
41
- ![predict__total_requests_per_second.png](assets%2Fpredict__total_requests_per_second.png)
42
-
43
- Optimized Predict endpoint:
44
-
45
- ![optimized_predict__total_requests_per_second.png](assets%2Foptimized_predict__total_requests_per_second.png)
46
-
47
- As we can see from the graphs, for the `/predict` endpoint, the failure rate started to increase linearly at the RPS
48
- of ~284 requests/second, and the 95th percentile response time was ~1100ms at this point. Then with the increase of
49
- the RPS, the number of successful requests was ~130 requests/second in average, with a high failure rate
50
- (~300 from ~400 requests/second).
51
-
52
- For the `/optimized_predict` endpoint, the failure was smaller than 3 requests/second (0.00625%) during the whole test,
53
- the average response time was increasing slightly with the increase of the RPS, and it reached ~120ms in average at
54
- the end of the test (> 480 requests/second), with a 95th percentile response time almost stable and smaller than 500ms.
55
-
56
- You can find check the reports for more details:
57
- - [predict__report.html](assets/predict__report.html)
58
- - [optimized_predict__report.html](assets/optimized_predict__report.html)
59
- ## Use cases
60
-
61
- The `AsyncBatcher` library can be used in any application that needs to handle asynchronous requests in batches,
62
- such as:
63
- - Serving machine learning models that optimize the batch processing (e.g. TensorFlow, PyTorch, Scikit-learn, etc.)
64
- - Storing multiple records in a database in a single query to optimize the I/O operations (or to reduce the cost of the
65
- database operations, e.g. AWS DynamoDB)
66
- - Sending multiple messages in a single request to optimize the network operations (or to reduce the cost of the network
67
- operations, e.g. Kafka, RabbitMQ, AWS SQS, AWS SNS, etc.)
68
-
File without changes