Skip to main content
This page covers the essential APIs for building multi-GPU applications with fal.distributed. We focus on the methods you’ll actually use in your code.

DistributedRunner

The DistributedRunner class orchestrates multiple GPU workers for distributed computation. It handles process management, inter-process communication via ZMQ, and coordination between worker processes.

Constructor

Parameters:
  • worker_cls (type[DistributedWorker]): Your custom worker class that inherits from DistributedWorker.
  • world_size (int): Total number of worker processes to spawn (typically equals num_gpus).
Example:

start()

Starts all distributed worker processes and initializes them.
Parameters:
  • timeout (int): Maximum time (in seconds) to wait for all workers to be ready. Default: 1800 (30 minutes).
  • **kwargs: Additional keyword arguments passed to each worker’s setup() method.
Raises:
  • RuntimeError: If processes are already running or fail to start.
  • TimeoutError: If workers don’t become ready within the timeout period.
Example:
What it does:
  1. Spawns world_size worker processes (one per GPU)
  2. Each worker runs its setup() method with the provided **kwargs
  3. Waits for all workers to signal “READY”
  4. Starts the keepalive timer if configured
  5. Returns when all workers are initialized and ready
This method must be called before using invoke() or stream(). It’s typically called once in your app’s setup() method.

invoke()

Executes the worker’s __call__() method across all GPUs and returns the final result from rank 0.
Parameters:
  • payload (dict[str, Any]): Dictionary of arguments to pass to each worker’s __call__() method. Default: {}.
  • timeout (int | None): Maximum time (in seconds) to wait for the result. If None, uses the runner’s default timeout. Default: None.
Returns:
  • Any: The result returned by rank 0 worker’s __call__() method.
Raises:
  • RuntimeError: If workers are not running or encounter an error during execution.
  • TimeoutError: If the operation exceeds the timeout.
Example:
How it works:
  1. Serializes the payload and sends it to all workers
  2. Each worker executes its __call__() method with streaming=False
  3. Workers coordinate using PyTorch distributed operations (e.g., dist.gather())
  4. Only rank 0 returns the result
  5. Result is deserialized and returned to the caller
Use invoke() for standard (non-streaming) requests where you need the final result only.

stream()

Streams intermediate results from workers during execution, useful for long-running operations like image generation or training.
Parameters:
  • payload (dict[str, Any]): Dictionary of arguments to pass to each worker’s __call__() method. Default: {}.
  • timeout (int | None): Maximum total time (in seconds) for the entire operation. Default: None (no limit).
  • streaming_timeout (int | None): Maximum time (in seconds) between consecutive yields. If no data is received within this period, raises TimeoutError. Default: None.
  • as_text_events (bool): If True, yields Server-Sent Events (SSE) formatted as bytes. If False, yields deserialized Python objects. Default: False.
Returns:
  • AsyncIterator[Any]: Async iterator yielding intermediate results and the final result.
Raises:
  • RuntimeError: If workers are not running, encounter an error, or yield no data.
  • TimeoutError: If the operation exceeds timeout or streaming_timeout.
Example:
How it works:
  1. Serializes the payload and sends it to all workers
  2. Each worker executes its __call__() method with streaming=True
  3. Workers can call self.add_streaming_result() to send intermediate updates
  4. The runner yields each intermediate result as it’s received
  5. After workers finish, yields the final result
  6. Automatically handles serialization based on as_text_events
Set as_text_events=True when using with StreamingResponse for browser-compatible Server-Sent Events.

DistributedWorker

The DistributedWorker class is the base class for your custom GPU workers. Each instance runs on a separate GPU and handles model loading, inference, or training. Create your own worker by inheriting from DistributedWorker and overriding the setup() and __call__() methods.

Properties

device

Returns the CUDA device assigned to this worker.
Returns:
  • torch.device: The PyTorch device for this worker, e.g., cuda:0, cuda:1, etc.
Example:

rank

The rank (ID) of this worker, from 0 to world_size-1.
Example:

world_size

Total number of workers in the distributed setup.
Example:

Methods to Override

setup()

Called once when the worker is initialized. Use this to load models, download weights, and prepare resources.
Parameters:
  • **kwargs: Any keyword arguments passed to runner.start().
Example:
Heavy operations like model loading should go in setup(), not __call__(), so they only happen once per worker.

call()

Called for each request. Implement your main processing logic here.
Parameters:
  • streaming (bool): True if called via runner.stream(), False if called via runner.invoke().
  • **kwargs: Arguments from the payload dict passed to runner.invoke() or runner.stream().
Returns:
  • Any: The result to return. Only rank 0’s return value is sent back to the caller.
Example:

Utility Methods

add_streaming_result()

Sends an intermediate result to the client during streaming.
Parameters:
  • result (Any): The data to stream. Can be a dict, PIL image, or any serializable object.
  • image_format (str): Image format for PIL images ("jpeg" or "png"). Default: "jpeg".
  • as_text_event (bool): If True, formats as Server-Sent Event. Must match the as_text_events parameter in runner.stream(). Default: False.
Example:
Only call add_streaming_result() from rank 0 to avoid duplicate messages to the client.

rank_print()

Prints a message with the worker’s rank prefix for easy debugging.
Parameters:
  • message (str): The message to print.
  • debug (bool): If True, prefixes with [debug]. Default: False.
Example:

Common Patterns

Pattern 1: Data Parallelism (Inference)

Each GPU processes different data independently:

Pattern 2: Distributed Data Parallel (Training)

All GPUs have the same model, process different batches, and sync gradients:

Pattern 3: Streaming with Progress Updates

Stream intermediate results during long-running operations:

Next Steps

Multi-GPU Inference Tutorial

Complete example with data parallelism

Multi-GPU Training Tutorial

Complete example with DDP training

Event Streaming

Learn about streaming intermediate results

Overview

High-level overview of multi-GPU workloads