chore: import upstream snapshot with attribution
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
# Parallel Function Test Agent
|
||||
|
||||
This agent demonstrates parallel function calling functionality in ADK. It includes multiple tools with different processing times to showcase how parallel execution improves performance compared to sequential execution.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multiple async tool types**: All functions use proper async patterns for true parallelism
|
||||
- **Thread safety testing**: Tools modify shared state to verify thread-safe operations
|
||||
- **Performance demonstration**: Clear time differences between parallel and sequential execution
|
||||
- **GIL-aware design**: Uses `await asyncio.sleep()` instead of `time.sleep()` to avoid blocking
|
||||
|
||||
## Tools
|
||||
|
||||
1. **get_weather(city)** - Async function, 2-second delay
|
||||
1. **get_currency_rate(from_currency, to_currency)** - Async function, 1.5-second delay
|
||||
1. **calculate_distance(city1, city2)** - Async function, 1-second delay
|
||||
1. **get_population(cities)** - Async function, 0.5 seconds per city
|
||||
|
||||
**Important**: All functions use `await asyncio.sleep()` instead of `time.sleep()` to ensure true parallel execution. Using `time.sleep()` would block Python's GIL and force sequential execution despite asyncio parallelism.
|
||||
|
||||
## Testing Parallel Function Calling
|
||||
|
||||
### Basic Parallel Test
|
||||
|
||||
```
|
||||
Get the weather for New York, London, and Tokyo
|
||||
```
|
||||
|
||||
Expected: 3 parallel get_weather calls (~2 seconds total instead of ~6 seconds sequential)
|
||||
|
||||
### Mixed Function Types Test
|
||||
|
||||
```
|
||||
Get the weather in Paris, the USD to EUR exchange rate, and the distance between New York and London
|
||||
```
|
||||
|
||||
Expected: 3 parallel async calls with different functions (~2 seconds total)
|
||||
|
||||
### Complex Parallel Test
|
||||
|
||||
```
|
||||
Compare New York and London by getting weather, population, and distance between them
|
||||
```
|
||||
|
||||
Expected: Multiple parallel calls combining different data types
|
||||
|
||||
### Performance Comparison Test
|
||||
|
||||
You can test the timing difference by asking for the same information in different ways:
|
||||
|
||||
**Sequential-style request:**
|
||||
|
||||
```
|
||||
First get the weather in New York, then get the weather in London, then get the weather in Tokyo
|
||||
```
|
||||
|
||||
*Expected time: ~6 seconds (2s + 2s + 2s)*
|
||||
|
||||
**Parallel-style request:**
|
||||
|
||||
```
|
||||
Get the weather in New York, London, and Tokyo
|
||||
```
|
||||
|
||||
*Expected time: ~2 seconds (max of parallel 2s delays)*
|
||||
|
||||
The parallel version should be **3x faster** due to concurrent execution.
|
||||
|
||||
## Thread Safety Testing
|
||||
|
||||
All tools modify the agent's state (`tool_context.state`) with request logs including timestamps. This helps verify that:
|
||||
|
||||
- Multiple tools can safely modify state concurrently
|
||||
- No race conditions occur during parallel execution
|
||||
- State modifications are preserved correctly
|
||||
|
||||
## Running the Agent
|
||||
|
||||
```bash
|
||||
# Start the agent in interactive mode
|
||||
adk run contributing/samples/parallel_functions
|
||||
|
||||
# Or use the web interface
|
||||
adk web
|
||||
```
|
||||
|
||||
## Example Queries
|
||||
|
||||
- "Get weather for New York, London, Tokyo, and Paris" *(4 parallel calls, ~2s total)*
|
||||
- "What's the USD to EUR rate and GBP to USD rate?" *(2 parallel calls, ~1.5s total)*
|
||||
- "Compare New York and San Francisco: weather, population, and distance" *(3 parallel calls, ~2s total)*
|
||||
- "Get population data for Tokyo, London, Paris, and Sydney" *(1 call with 4 cities, ~2s total)*
|
||||
- "What's the weather in Paris and the distance from Paris to London?" *(2 parallel calls, ~2s total)*
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### ❌ Problem: Functions still execute sequentially (6+ seconds for 3 weather calls)
|
||||
|
||||
**Root Cause**: Using blocking operations like `time.sleep()` in function implementations.
|
||||
|
||||
**Solution**: Always use async patterns:
|
||||
|
||||
```python
|
||||
# ❌ Wrong - blocks the GIL, forces sequential execution
|
||||
def my_tool():
|
||||
time.sleep(2) # Blocks entire event loop
|
||||
|
||||
# ✅ Correct - allows true parallelism
|
||||
async def my_tool():
|
||||
await asyncio.sleep(2) # Non-blocking, parallel-friendly
|
||||
```
|
||||
|
||||
### ✅ Verification: Check execution timing
|
||||
|
||||
- Parallel execution: ~2 seconds for 3 weather calls
|
||||
- Sequential execution: ~6 seconds for 3 weather calls
|
||||
- If you see 6+ seconds, your functions are blocking the GIL
|
||||
Reference in New Issue
Block a user