Asynchronous Client API
The AsyncUESynthClient
provides a high-performance, non-blocking API designed for real-time simulations, batch processing, and scenarios requiring thousands of operations per second.
Overview
The asynchronous client offers:
High throughput - 100-1000+ requests/second vs 10-50 for sync
Low latency - Minimal waiting between operations
Concurrent operations - Multiple requests in parallel
Streaming support - Bidirectional data streaming
Non-blocking - Doesn't freeze while waiting for responses
Performance Comparison
Throughput
~10-50 req/sec
~100-1000+ req/sec
Latency
High accumulation
Minimal
Concurrent ops
Sequential only
Full parallelism
Use case
Simple scripts
High-performance sims
Getting Started
import asyncio
from uesynth import AsyncUESynthClient
async def main():
# Connect to UESynth
client = AsyncUESynthClient()
await client.connect()
try:
# Your async code here...
pass
finally:
# Always disconnect
await client.disconnect()
# Run the async function
asyncio.run(main())
Client Configuration
Basic Connection
# Default connection
client = AsyncUESynthClient()
# Custom connection
client = AsyncUESynthClient(
host="192.168.1.100",
port=50052,
timeout=10.0,
stream_buffer_size=2048
)
Advanced Options
client = AsyncUESynthClient(
host="localhost",
port=50051,
timeout=5.0,
max_concurrent_requests=500,
stream_buffer_size=4096,
enable_compression=True,
grpc_options=[
('grpc.keepalive_time_ms', 30000),
('grpc.http2.max_pings_without_data', 0)
]
)
Core Methods
Connection Management
connect()
connect()
Establish connection and initialize streaming.
client = AsyncUESynthClient()
await client.connect()
disconnect()
disconnect()
Close connection and clean up resources.
await client.disconnect()
is_connected()
is_connected()
Check connection status.
if await client.is_connected():
print("Connected to UESynth")
ping()
ping()
Test server responsiveness.
latency = await client.ping()
print(f"Server latency: {latency}ms")
Request Modes
The async client supports two operation modes:
1. Streaming Mode (Non-blocking)
Operations return request IDs immediately and complete asynchronously.
# Send request (non-blocking, returns immediately)
request_id = await client.camera.set_location(x=100, y=200, z=50)
# Send capture request (non-blocking)
capture_id = await client.capture.rgb()
# Get the captured frame when ready
frame = await client.get_latest_frame()
2. Direct Mode (Blocking)
Operations wait for completion and return results directly.
# Direct operations (wait for completion)
location = await client.camera.get_location_direct()
rgb_image = await client.capture.rgb_direct()
Camera Control (Streaming)
Position and Rotation
camera.set_location(x, y, z)
camera.set_location(x, y, z)
Set camera position (non-blocking).
# Returns request ID immediately
request_id = await client.camera.set_location(x=100, y=200, z=50)
print(f"Camera move request: {request_id}")
camera.set_rotation(pitch, yaw, roll)
camera.set_rotation(pitch, yaw, roll)
Set camera rotation (non-blocking).
request_id = await client.camera.set_rotation(pitch=-30, yaw=45, roll=0)
Camera Settings
camera.set_fov(fov)
camera.set_fov(fov)
Set field of view (non-blocking).
request_id = await client.camera.set_fov(75.0)
Camera Control (Direct)
Position and Rotation
camera.get_location_direct()
camera.get_location_direct()
Get camera position (blocking, returns result).
location = await client.camera.get_location_direct()
print(f"Camera at: {location.x}, {location.y}, {location.z}")
camera.get_rotation_direct()
camera.get_rotation_direct()
Get camera rotation (blocking, returns result).
rotation = await client.camera.get_rotation_direct()
print(f"Camera rotation: {rotation.pitch}, {rotation.yaw}, {rotation.roll}")
camera.set_location_direct(x, y, z)
camera.set_location_direct(x, y, z)
Set camera position and wait for completion.
await client.camera.set_location_direct(x=100, y=200, z=50)
print("Camera position updated")
Data Capture (Streaming)
Image Capture
capture.rgb(width=None, height=None)
capture.rgb(width=None, height=None)
Capture RGB image (non-blocking).
# Start capture (returns immediately)
request_id = await client.capture.rgb(width=1920, height=1080)
# Get result when ready
frame = await client.get_latest_frame()
if frame is not None:
import cv2
cv2.imwrite("captured.png", frame)
capture.depth(width=None, height=None)
capture.depth(width=None, height=None)
Capture depth map (non-blocking).
request_id = await client.capture.depth()
capture.segmentation(width=None, height=None)
capture.segmentation(width=None, height=None)
Capture segmentation (non-blocking).
request_id = await client.capture.segmentation()
Data Capture (Direct)
Image Capture
capture.rgb_direct(width=None, height=None)
capture.rgb_direct(width=None, height=None)
Capture RGB image and return result immediately.
# Wait for capture and get result
rgb_image = await client.capture.rgb_direct(width=1920, height=1080)
print(f"Captured image: {rgb_image.shape}")
capture.depth_direct(width=None, height=None)
capture.depth_direct(width=None, height=None)
Capture depth map directly.
depth_map = await client.capture.depth_direct()
capture.all_modalities_direct(width=None, height=None)
capture.all_modalities_direct(width=None, height=None)
Capture all data types directly.
data = await client.capture.all_modalities_direct(width=1024, height=768)
rgb = data['rgb']
depth = data['depth']
segmentation = data['segmentation']
Frame Management
Getting Captured Data
get_latest_frame()
get_latest_frame()
Get the most recently captured frame.
# Start a capture
await client.capture.rgb()
# Wait a bit and get the result
await asyncio.sleep(0.1)
frame = await client.get_latest_frame()
if frame is not None:
print(f"Got frame: {frame.shape}")
else:
print("No frame available yet")
get_frame_by_id(request_id)
get_frame_by_id(request_id)
Get a specific frame by its request ID.
# Start capture and remember the ID
request_id = await client.capture.rgb()
# Get the specific frame
frame = await client.get_frame_by_id(request_id)
wait_for_frame(request_id, timeout=5.0)
wait_for_frame(request_id, timeout=5.0)
Wait for a specific frame to be ready.
# Start capture
request_id = await client.capture.rgb()
# Wait for it to complete
frame = await client.wait_for_frame(request_id, timeout=10.0)
Object Manipulation
Transform Control (Streaming)
objects.set_location(name, x, y, z)
objects.set_location(name, x, y, z)
Move object (non-blocking).
request_id = await client.objects.set_location("MyActor", x=100, y=200, z=50)
objects.set_rotation(name, pitch, yaw, roll)
objects.set_rotation(name, pitch, yaw, roll)
Rotate object (non-blocking).
request_id = await client.objects.set_rotation("MyActor", pitch=0, yaw=45, roll=0)
Transform Control (Direct)
objects.set_transform_direct(name, x, y, z, pitch=0, yaw=0, roll=0)
objects.set_transform_direct(name, x, y, z, pitch=0, yaw=0, roll=0)
Set complete transform and wait for completion.
await client.objects.set_transform_direct(
"MyActor",
x=100, y=200, z=50,
pitch=0, yaw=45, roll=0
)
objects.get_transform_direct(name)
objects.get_transform_direct(name)
Get object transform directly.
transform = await client.objects.get_transform_direct("MyActor")
print(f"Transform: {transform}")
High-Performance Patterns
Concurrent Operations
import asyncio
async def capture_multiple_views():
client = AsyncUESynthClient()
await client.connect()
try:
# Start multiple operations concurrently
tasks = []
for i in range(10):
x = i * 100
# Start camera move (non-blocking)
move_task = client.camera.set_location(x=x, y=0, z=50)
# Start capture (non-blocking)
capture_task = client.capture.rgb()
tasks.extend([move_task, capture_task])
# Wait for all to complete
await asyncio.gather(*tasks)
# Collect all frames
frames = []
for _ in range(10):
frame = await client.get_latest_frame()
if frame is not None:
frames.append(frame)
print(f"Captured {len(frames)} frames")
finally:
await client.disconnect()
Real-time Simulation Loop
async def real_time_simulation():
client = AsyncUESynthClient()
await client.connect()
try:
timestep = 0
while timestep < 1000:
# Move camera (non-blocking)
await client.camera.set_location(
x=timestep * 10,
y=100,
z=50
)
# Move objects (non-blocking)
await client.objects.set_location(
"Car_01",
x=timestep * 5,
y=0,
z=0
)
# Capture frame (non-blocking)
await client.capture.rgb()
# Get latest frame if available
frame = await client.get_latest_frame()
if frame is not None:
# Process frame...
pass
# Small delay to prevent overwhelming
await asyncio.sleep(0.01)
timestep += 1
finally:
await client.disconnect()
Batch Processing
async def batch_capture():
client = AsyncUESynthClient()
await client.connect()
try:
# Prepare batch of positions
positions = [(i*50, j*50, 100) for i in range(10) for j in range(10)]
# Start all operations (non-blocking)
request_ids = []
for x, y, z in positions:
await client.camera.set_location(x=x, y=y, z=z)
request_id = await client.capture.rgb()
request_ids.append(request_id)
# Collect all results
frames = []
for request_id in request_ids:
frame = await client.wait_for_frame(request_id)
frames.append(frame)
print(f"Batch captured {len(frames)} frames")
finally:
await client.disconnect()
Error Handling
import asyncio
from uesynth import AsyncUESynthClient, UESynthError
async def robust_client():
client = AsyncUESynthClient()
try:
await client.connect()
# Your operations here
await client.capture.rgb_direct()
except UESynthError as e:
print(f"UESynth error: {e}")
except asyncio.TimeoutError as e:
print(f"Operation timed out: {e}")
except ConnectionError as e:
print(f"Connection lost: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
finally:
try:
await client.disconnect()
except:
pass # Ignore cleanup errors
Context Manager
from uesynth import AsyncUESynthClient
async def with_context_manager():
async with AsyncUESynthClient() as client:
# Client automatically connects
frame = await client.capture.rgb_direct()
# Client automatically disconnects
Performance Tips
1. Use Streaming for High Throughput
# ✅ High performance - streaming mode
for i in range(1000):
await client.camera.set_location(x=i, y=0, z=50) # Non-blocking
await client.capture.rgb() # Non-blocking
# ❌ Lower performance - direct mode
for i in range(1000):
await client.camera.set_location_direct(x=i, y=0, z=50) # Blocking
frame = await client.capture.rgb_direct() # Blocking
2. Minimize Await Points
# ✅ Better - batch operations
tasks = []
for i in range(100):
tasks.append(client.camera.set_location(x=i, y=0, z=50))
await asyncio.gather(*tasks)
# ❌ Slower - individual awaits
for i in range(100):
await client.camera.set_location(x=i, y=0, z=50)
3. Configure Buffer Sizes
# For high-frequency operations
client = AsyncUESynthClient(
stream_buffer_size=8192, # Large buffer
max_concurrent_requests=1000 # High concurrency
)
Complete Example
import asyncio
import cv2
from uesynth import AsyncUESynthClient
async def high_performance_data_collection():
"""Collect 1000 frames as fast as possible."""
async with AsyncUESynthClient(
stream_buffer_size=4096,
max_concurrent_requests=500
) as client:
print("🚀 Starting high-performance data collection...")
# Generate camera trajectory
trajectory = [
(i * 10, 0, 50 + i * 2)
for i in range(1000)
]
# Start all operations (non-blocking)
request_ids = []
start_time = asyncio.get_event_loop().time()
for i, (x, y, z) in enumerate(trajectory):
# Move camera
await client.camera.set_location(x=x, y=y, z=z)
# Start capture
request_id = await client.capture.rgb()
request_ids.append(request_id)
# Small delay to prevent overwhelming
if i % 100 == 0:
await asyncio.sleep(0.01)
# Collect all frames
frames_collected = 0
for i, request_id in enumerate(request_ids):
try:
frame = await client.wait_for_frame(request_id, timeout=1.0)
if frame is not None:
cv2.imwrite(f"frame_{i:06d}.png", frame)
frames_collected += 1
except asyncio.TimeoutError:
print(f"Frame {i} timed out")
end_time = asyncio.get_event_loop().time()
duration = end_time - start_time
print(f"✅ Collected {frames_collected}/1000 frames in {duration:.2f}s")
print(f"📊 Average: {frames_collected/duration:.1f} frames/second")
if __name__ == "__main__":
asyncio.run(high_performance_data_collection())
Next Steps
Learn about Camera Controls for advanced camera features
Explore Performance Optimization for maximum throughput
Check out Async Examples for more patterns
Last updated