Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Ray schedules independent Python tasks and tracks their progress for you. In this notebook, you start Ray on attached 1xA10 compute, submit eight GPU tasks without waiting for each one to finish, and use the Ray dashboard to watch them run one at a time on the available GPU.
Note
This example requires the Databricks AI environment version 5 or above.
Requirements
This notebook requires AI Runtime with the AI v5 environment. The walkthrough uses 1xA10 attached GPU compute so that you can observe Ray queueing work.
To connect the notebook:
- Select Connect at the top of the notebook.
- Select Serverless GPU.
- In the Environment side panel, set Accelerator to 1xA10.
- Select AI v5 as the base environment.
- Select Apply, then select Confirm.
AI v5 includes Ray and CUDA-enabled PyTorch, so this example does not install additional packages. To see all eight tasks run at the same time, you can instead attach the notebook to 8xH100 compute and rerun it.
Initialize Ray
Start Ray for the notebook session with ray_init(). The function displays information about the Ray context and prints a dashboard link that works through the Databricks driver proxy.
import ray
from serverless_gpu import ray_init
ray_init()
Inspect Ray resources
Before you submit work, check the resources that Ray discovered. With 1xA10 compute, the cluster should report one GPU.
from pprint import pprint
cluster_resources = ray.cluster_resources()
available_resources = ray.available_resources()
pprint(
{
"cluster_resources": cluster_resources,
"available_resources": available_resources,
},
sort_dicts=False,
)
if cluster_resources.get("GPU", 0) < 1:
raise RuntimeError(
"Ray did not detect a GPU. Attach the notebook to 1xA10 or 8xH100 compute, then rerun it."
)
Define a GPU task
Decorating a function with @ray.remote(num_gpus=1) creates a Ray task that reserves one GPU each time it runs. This task performs a small CUDA calculation and returns details about the GPU it used.
The sleep call keeps each task active long enough to inspect it in the dashboard. This pause is only for dashboard exploration and is not meant to be used as a benchmark.
@ray.remote(num_gpus=1)
def run_gpu_task(task_id: int, inspection_seconds: int) -> dict:
import os
import time
import ray
import torch
values = torch.arange(1, 5, dtype=torch.float32, device="cuda") + task_id
computation_result = torch.square(values).sum().item()
torch.cuda.synchronize()
time.sleep(inspection_seconds)
return {
"task_id": task_id,
"ray_gpu_ids": ray.get_gpu_ids(),
"cuda_visible_devices": os.environ.get("CUDA_VISIBLE_DEVICES"),
"gpu_model": torch.cuda.get_device_name(0),
"computation_result": computation_result,
}
Submit tasks asynchronously
Before you run the next cell, open the dashboard link printed by ray_init(). From the Jobs page, open the running job and watch the task list after submission. With 1xA10 compute, you should see one task running while the other seven wait for GPU capacity. With 8xH100 compute, all eight tasks can run at the same time.
Each .remote() call submits a task without waiting for it to finish and returns an object reference.
task_refs = [run_gpu_task.remote(task_id, inspection_seconds=10) for task_id in range(8)]
print(f"Submitted {len(task_refs)} tasks.")
print(f"Each submission returned a {type(task_refs[0]).__name__}.")
Retrieve results
After you have inspected the dashboard, pass the object references to ray.get(). Ray waits for the tasks to finish and returns their results in submission order.
results = ray.get(task_refs)
pprint(results, sort_dicts=False)
With 1xA10 compute, the results show that all eight tasks used the same GPU one after another. If you rerun the notebook with 8xH100 compute, Ray can schedule all eight tasks at the same time without any code changes.