-
Notifications
You must be signed in to change notification settings - Fork 47
Expand file tree
/
Copy pathpool.py
More file actions
114 lines (89 loc) · 3.24 KB
/
Copy pathpool.py
File metadata and controls
114 lines (89 loc) · 3.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright The Lance Authors
import logging
import threading
from collections.abc import Iterator
from contextlib import contextmanager
from typing import Any, Optional
from ray.util.multiprocessing import Pool
logger = logging.getLogger(__name__)
_GLOBAL_POOL: Any | None = None
_GLOBAL_POOL_PROCESSES: int | None = None
_GLOBAL_POOL_LOCK = threading.RLock()
def _read_pool_processes(pool: Any) -> int | None:
for attr in ("processes", "_processes", "_num_processes"):
value = getattr(pool, attr, None)
if isinstance(value, int):
return value
return None
def _warn_if_process_count_differs(requested_processes: int) -> None:
if _GLOBAL_POOL_PROCESSES is None:
return
if requested_processes == _GLOBAL_POOL_PROCESSES:
return
logger.warning(
"Reusing global Ray Pool with %d processes; requested %d workers will be "
"ignored while the global Pool is active.",
_GLOBAL_POOL_PROCESSES,
requested_processes,
)
def set_global_pool(pool: Any | None) -> None:
"""Set a process-wide Ray Pool for Lance-Ray operations to reuse.
Passing ``None`` clears the global Pool reference without closing it.
"""
global _GLOBAL_POOL, _GLOBAL_POOL_PROCESSES
with _GLOBAL_POOL_LOCK:
_GLOBAL_POOL = pool
_GLOBAL_POOL_PROCESSES = (
_read_pool_processes(pool) if pool is not None else None
)
def get_global_pool() -> Any | None:
"""Return the currently configured global Ray Pool, if any."""
with _GLOBAL_POOL_LOCK:
return _GLOBAL_POOL
def init_global_pool(
processes: int,
ray_remote_args: Optional[dict[str, Any]] = None,
) -> Any:
"""Create and register a global Ray Pool if one does not already exist."""
if processes <= 0:
raise ValueError(f"processes must be positive, got {processes}")
global _GLOBAL_POOL, _GLOBAL_POOL_PROCESSES
with _GLOBAL_POOL_LOCK:
if _GLOBAL_POOL is not None:
_warn_if_process_count_differs(processes)
return _GLOBAL_POOL
_GLOBAL_POOL = Pool(processes=processes, ray_remote_args=ray_remote_args)
_GLOBAL_POOL_PROCESSES = processes
return _GLOBAL_POOL
def clear_global_pool(*, close: bool = False, join: bool = True) -> None:
"""Clear the global Pool reference, optionally closing and joining it."""
global _GLOBAL_POOL, _GLOBAL_POOL_PROCESSES
with _GLOBAL_POOL_LOCK:
pool = _GLOBAL_POOL
_GLOBAL_POOL = None
_GLOBAL_POOL_PROCESSES = None
if close and pool is not None:
pool.close()
if join:
pool.join()
@contextmanager
def get_or_create_pool(
*,
processes: int,
ray_remote_args: Optional[dict[str, Any]],
) -> Iterator[Any]:
"""Yield the global Pool if present, otherwise a local close-and-join Pool."""
with _GLOBAL_POOL_LOCK:
pool = _GLOBAL_POOL
if pool is not None:
_warn_if_process_count_differs(processes)
if pool is not None:
yield pool
return
local_pool = Pool(processes=processes, ray_remote_args=ray_remote_args)
try:
yield local_pool
finally:
local_pool.close()
local_pool.join()