183 lines
5.7 KiB
Python
183 lines
5.7 KiB
Python
"""Tests for ray.util.multiprocessing that require a standalone Ray cluster per test.
|
|
|
|
Tests that can run on a shared Ray cluster fixture should go in test_multiprocessing.py
|
|
"""
|
|
import math
|
|
import multiprocessing as mp
|
|
import os
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
import ray
|
|
from ray._private.test_utils import persistent_gcs_test_enabled
|
|
from ray.util.multiprocessing import Pool
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def ray_init_4_cpu_shared():
|
|
yield ray.init(num_cpus=4)
|
|
|
|
|
|
@pytest.fixture
|
|
def pool_4_processes(ray_init_4_cpu_shared):
|
|
pool = Pool(processes=4)
|
|
yield pool
|
|
pool.terminate()
|
|
pool.join()
|
|
|
|
|
|
@pytest.fixture
|
|
def pool_4_processes_python_multiprocessing_lib():
|
|
pool = mp.Pool(processes=4)
|
|
yield pool
|
|
pool.terminate()
|
|
pool.join()
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
persistent_gcs_test_enabled(),
|
|
reason="Starts multiple Ray instances in parallel with the same namespace.",
|
|
)
|
|
def test_ray_init(shutdown_only):
|
|
def getpid(i: int):
|
|
return os.getpid()
|
|
|
|
def check_pool_size(pool, size: int):
|
|
assert len(set(pool.map(getpid, range(size)))) == size
|
|
|
|
# Check that starting a pool starts ray if not initialized.
|
|
assert not ray.is_initialized()
|
|
with Pool(processes=4) as pool:
|
|
assert ray.is_initialized()
|
|
check_pool_size(pool, 4)
|
|
assert int(ray.cluster_resources()["CPU"]) == 4
|
|
pool.join()
|
|
|
|
# Check that starting a pool doesn't affect ray if there is a local
|
|
# ray cluster running.
|
|
assert ray.is_initialized()
|
|
assert int(ray.cluster_resources()["CPU"]) == 4
|
|
with Pool(processes=2) as pool:
|
|
assert ray.is_initialized()
|
|
check_pool_size(pool, 2)
|
|
assert int(ray.cluster_resources()["CPU"]) == 4
|
|
pool.join()
|
|
|
|
# Check that trying to start a pool on an existing ray cluster throws an
|
|
# error if there aren't enough CPUs for the number of processes.
|
|
assert ray.is_initialized()
|
|
assert int(ray.cluster_resources()["CPU"]) == 4
|
|
with pytest.raises(ValueError):
|
|
Pool(processes=8)
|
|
assert int(ray.cluster_resources()["CPU"]) == 4
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
persistent_gcs_test_enabled(),
|
|
reason="Starts multiple Ray instances in parallel with the same namespace.",
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"ray_start_cluster",
|
|
[
|
|
{
|
|
"num_cpus": 1,
|
|
"num_nodes": 1,
|
|
"do_init": False,
|
|
}
|
|
],
|
|
indirect=True,
|
|
)
|
|
def test_connect_to_ray(monkeypatch, ray_start_cluster):
|
|
def getpid(args):
|
|
return os.getpid()
|
|
|
|
def check_pool_size(pool, size):
|
|
args = [tuple() for _ in range(size)]
|
|
assert len(set(pool.map(getpid, args))) == size
|
|
|
|
# Use different numbers of CPUs to distinguish between starting a local
|
|
# ray cluster and connecting to an existing one.
|
|
ray.init(address=ray_start_cluster.address)
|
|
existing_cluster_cpus = int(ray.cluster_resources()["CPU"])
|
|
local_cluster_cpus = existing_cluster_cpus + 1
|
|
ray.shutdown()
|
|
|
|
# Check that starting a pool connects to the running ray cluster by default.
|
|
assert not ray.is_initialized()
|
|
with Pool() as pool:
|
|
assert ray.is_initialized()
|
|
check_pool_size(pool, existing_cluster_cpus)
|
|
assert int(ray.cluster_resources()["CPU"]) == existing_cluster_cpus
|
|
pool.join()
|
|
ray.shutdown()
|
|
|
|
# Check that starting a pool connects to a running ray cluster if
|
|
# ray_address is set to the cluster address.
|
|
assert not ray.is_initialized()
|
|
with Pool(ray_address=ray_start_cluster.address) as pool:
|
|
check_pool_size(pool, existing_cluster_cpus)
|
|
assert int(ray.cluster_resources()["CPU"]) == existing_cluster_cpus
|
|
pool.join()
|
|
ray.shutdown()
|
|
|
|
# Check that starting a pool connects to a running ray cluster if
|
|
# RAY_ADDRESS is set to the cluster address.
|
|
assert not ray.is_initialized()
|
|
monkeypatch.setenv("RAY_ADDRESS", ray_start_cluster.address)
|
|
with Pool() as pool:
|
|
check_pool_size(pool, existing_cluster_cpus)
|
|
assert int(ray.cluster_resources()["CPU"]) == existing_cluster_cpus
|
|
pool.join()
|
|
ray.shutdown()
|
|
|
|
# Check that trying to start a pool on an existing ray cluster throws an
|
|
# error if there aren't enough CPUs for the number of processes.
|
|
assert not ray.is_initialized()
|
|
with pytest.raises(Exception):
|
|
Pool(processes=existing_cluster_cpus + 1)
|
|
assert int(ray.cluster_resources()["CPU"]) == existing_cluster_cpus
|
|
ray.shutdown()
|
|
|
|
# Check that starting a pool starts a local ray cluster if ray_address="local".
|
|
assert not ray.is_initialized()
|
|
with Pool(processes=local_cluster_cpus, ray_address="local") as pool:
|
|
check_pool_size(pool, local_cluster_cpus)
|
|
assert int(ray.cluster_resources()["CPU"]) == local_cluster_cpus
|
|
pool.join()
|
|
ray.shutdown()
|
|
|
|
# Check that starting a pool starts a local ray cluster if RAY_ADDRESS="local".
|
|
assert not ray.is_initialized()
|
|
monkeypatch.setenv("RAY_ADDRESS", "local")
|
|
with Pool(processes=local_cluster_cpus) as pool:
|
|
check_pool_size(pool, local_cluster_cpus)
|
|
assert int(ray.cluster_resources()["CPU"]) == local_cluster_cpus
|
|
pool.join()
|
|
ray.shutdown()
|
|
|
|
|
|
def test_maxtasksperchild(shutdown_only):
|
|
with Pool(processes=5, maxtasksperchild=1) as pool:
|
|
assert len(set(pool.map(lambda _: os.getpid(), range(20)))) == 20
|
|
pool.join()
|
|
|
|
|
|
def test_deadlock_avoidance_in_recursive_tasks(shutdown_only):
|
|
ray.init(num_cpus=1)
|
|
|
|
def poolit_a(_):
|
|
with Pool() as pool:
|
|
return list(pool.map(math.sqrt, range(0, 2, 1)))
|
|
|
|
def poolit_b():
|
|
with Pool() as pool:
|
|
return list(pool.map(poolit_a, range(2, 4, 1)))
|
|
|
|
result = poolit_b()
|
|
assert result == [[0.0, 1.0], [0.0, 1.0]]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(pytest.main(["-sv", __file__]))
|