update parallel tutorial

This commit is contained in:
zachary62
2025-03-20 13:20:10 -04:00
parent 60d9631204
commit 25b742e29a
15 changed files with 260 additions and 1402 deletions
@@ -0,0 +1,41 @@
# Sequential vs Parallel Processing
Demonstrates how AsyncParallelBatchNode accelerates processing by 3x over AsyncBatchNode.
## Features
- Processes identical tasks with two approaches
- Compares sequential vs parallel execution time
- Shows 3x speed improvement with parallel processing
## Run It
```bash
pip install pocketflow
python main.py
```
## Output
```
=== Running Sequential (AsyncBatchNode) ===
[Sequential] Summarizing file1.txt...
[Sequential] Summarizing file2.txt...
[Sequential] Summarizing file3.txt...
=== Running Parallel (AsyncParallelBatchNode) ===
[Parallel] Summarizing file1.txt...
[Parallel] Summarizing file2.txt...
[Parallel] Summarizing file3.txt...
Sequential took: 3.00 seconds
Parallel took: 1.00 seconds
```
## Key Points
- **Sequential**: Total time = sum of all item times
- Good for: Rate-limited APIs, maintaining order
- **Parallel**: Total time ≈ longest single item time
- Good for: I/O-bound tasks, independent operations
+103
View File
@@ -0,0 +1,103 @@
import asyncio
import time
from pocketflow import AsyncBatchNode, AsyncParallelBatchNode, AsyncFlow
####################################
# Dummy async function (1s delay)
####################################
async def dummy_llm_summarize(text):
"""Simulates an async LLM call that takes 1 second."""
await asyncio.sleep(1)
return f"Summarized({len(text)} chars)"
###############################################
# 1) AsyncBatchNode (sequential) version
###############################################
class SummariesAsyncNode(AsyncBatchNode):
"""
Processes items sequentially in an async manner.
The next item won't start until the previous item has finished.
"""
async def prep_async(self, shared):
# Return a list of items to process.
# Each item is (filename, content).
return list(shared["data"].items())
async def exec_async(self, item):
filename, content = item
print(f"[Sequential] Summarizing {filename}...")
summary = await dummy_llm_summarize(content)
return (filename, summary)
async def post_async(self, shared, prep_res, exec_res_list):
# exec_res_list is a list of (filename, summary)
shared["sequential_summaries"] = dict(exec_res_list)
return "done_sequential"
###############################################
# 2) AsyncParallelBatchNode (concurrent) version
###############################################
class SummariesAsyncParallelNode(AsyncParallelBatchNode):
"""
Processes items in parallel. Many LLM calls start at once.
"""
async def prep_async(self, shared):
return list(shared["data"].items())
async def exec_async(self, item):
filename, content = item
print(f"[Parallel] Summarizing {filename}...")
summary = await dummy_llm_summarize(content)
return (filename, summary)
async def post_async(self, shared, prep_res, exec_res_list):
shared["parallel_summaries"] = dict(exec_res_list)
return "done_parallel"
###############################################
# Demo comparing the two approaches
###############################################
async def main():
# We'll use the same data for both flows
shared_data = {
"data": {
"file1.txt": "Hello world 1",
"file2.txt": "Hello world 2",
"file3.txt": "Hello world 3",
}
}
# 1) Run the sequential version
seq_node = SummariesAsyncNode()
seq_flow = AsyncFlow(start=seq_node)
print("\n=== Running Sequential (AsyncBatchNode) ===")
t0 = time.time()
await seq_flow.run_async(shared_data)
t1 = time.time()
# 2) Run the parallel version
par_node = SummariesAsyncParallelNode()
par_flow = AsyncFlow(start=par_node)
print("\n=== Running Parallel (AsyncParallelBatchNode) ===")
t2 = time.time()
await par_flow.run_async(shared_data)
t3 = time.time()
# Show times
print("\n--- Results ---")
print(f"Sequential Summaries: {shared_data.get('sequential_summaries')}")
print(f"Parallel Summaries: {shared_data.get('parallel_summaries')}")
print(f"Sequential took: {t1 - t0:.2f} seconds")
print(f"Parallel took: {t3 - t2:.2f} seconds")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1 @@
pocketflow>=0.0.1