Skip to content

Commit 9ec8ad4

Browse files
Add explicit worker initializer support
1 parent d5a1b38 commit 9ec8ad4

8 files changed

Lines changed: 57 additions & 10 deletions

File tree

src/plaid/storage/backend_api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def generate_to_disk(
6565
num_proc: int = 1,
6666
verbose: bool = False,
6767
sample_callback: Optional[SampleCallback] = None,
68+
worker_initializer: Optional[Callable[[], None]] = None,
6869
) -> None:
6970
"""Generate and save a dataset dictionary to local storage.
7071

src/plaid/storage/cgns/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from collections.abc import Iterable
44
from pathlib import Path
5-
from typing import Any, Mapping, Optional, Union
5+
from typing import Any, Callable, Mapping, Optional, Union
66

77
from datasets import IterableDataset
88

@@ -62,8 +62,9 @@ def generate_to_disk(
6262
num_proc: int = 1,
6363
verbose: bool = False,
6464
sample_callback: Optional[SampleCallback] = None,
65+
worker_initializer: Optional[Callable[[], None]] = None,
6566
) -> None:
66-
return generate_datasetdict_to_disk(
67+
kwargs = dict(
6768
output_folder=output_folder,
6869
generators=generators,
6970
variable_schema=variable_schema,
@@ -72,6 +73,9 @@ def generate_to_disk(
7273
verbose=verbose,
7374
sample_callback=sample_callback,
7475
)
76+
if worker_initializer is not None:
77+
kwargs["worker_initializer"] = worker_initializer
78+
return generate_datasetdict_to_disk(**kwargs)
7579

7680
@staticmethod
7781
def push_local_to_hub(

src/plaid/storage/cgns/writer.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def generate_datasetdict_to_disk(
5757
num_proc: int = 1,
5858
verbose: bool = False,
5959
sample_callback: Optional[SampleCallback] = None,
60+
worker_initializer: Optional[Callable[[], None]] = None,
6061
) -> None:
6162
"""Generates and saves a dataset to disk in CGNS format.
6263
@@ -69,6 +70,9 @@ def generate_datasetdict_to_disk(
6970
verbose: Whether to show progress.
7071
sample_callback: Optional callback invoked with the written sample and its
7172
context. In parallel mode, it must be picklable and process-safe.
73+
worker_initializer: Optional callable executed once when each worker
74+
process starts. It must be picklable when using the ``spawn`` start
75+
method.
7276
"""
7377
output_folder = Path(output_folder)
7478

@@ -114,7 +118,10 @@ def generate_datasetdict_to_disk(
114118
# If your stack is sensitive to fork, switch to spawn:
115119
# ctx = mp.get_context("spawn")
116120
# with ctx.Pool(processes=num_proc) as pool:
117-
with mp.Pool(processes=num_proc) as pool:
121+
with mp.Pool(
122+
processes=num_proc,
123+
initializer=worker_initializer,
124+
) as pool:
118125
with tqdm(
119126
total=total_samples,
120127
desc=f"Writing {split_name} split",

src/plaid/storage/common/preprocessor.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ def preprocess_splits(
320320
gen_kwargs: Optional[dict[str, dict[str, Any]]] = None,
321321
num_proc: int = 1,
322322
verbose: bool = True,
323+
worker_initializer: Optional[Callable[[], None]] = None,
323324
) -> tuple[
324325
dict[str, set[str]],
325326
dict[str, dict[str, Any]],
@@ -349,6 +350,8 @@ def preprocess_splits(
349350
Number of worker processes to use for shard-level parallelism. Defaults to 1.
350351
verbose (bool, optional):
351352
If True, displays progress bars. Defaults to True.
353+
worker_initializer (callable, optional):
354+
Callable executed once when each worker process starts. Defaults to None.
352355
353356
Returns:
354357
tuple:
@@ -400,7 +403,7 @@ def preprocess_splits(
400403
shards_data = []
401404

402405
try:
403-
with mp.Pool(n_proc) as pool:
406+
with mp.Pool(n_proc, initializer=worker_initializer) as pool:
404407
results = [
405408
pool.apply_async(
406409
_process_shard_debug,
@@ -522,6 +525,7 @@ def preprocess(
522525
gen_kwargs: Optional[dict[str, dict[str, Any]]] = None,
523526
num_proc: int = 1,
524527
verbose: bool = True,
528+
worker_initializer: Optional[Callable[[], None]] = None,
525529
) -> tuple[
526530
dict[str, dict[str, Any]],
527531
dict[str, Any],
@@ -536,6 +540,9 @@ def preprocess(
536540
gen_kwargs: Optional generator kwargs for parallel processing.
537541
num_proc: Number of processes.
538542
verbose: Whether to show progress.
543+
worker_initializer: Optional callable executed once when each worker
544+
process starts. It must be picklable when using the ``spawn`` start
545+
method.
539546
540547
Returns:
541548
tuple: A 5-tuple ``(split_flat_cst, variable_schema, constant_schema,
@@ -548,7 +555,13 @@ def preprocess(
548555
global_cgns_types,
549556
global_feature_types,
550557
split_n_samples,
551-
) = preprocess_splits(generators, gen_kwargs, num_proc, verbose)
558+
) = preprocess_splits(
559+
generators,
560+
gen_kwargs,
561+
num_proc,
562+
verbose,
563+
worker_initializer,
564+
)
552565

553566
# --- build features ---
554567
var_features = sorted(list(set().union(*split_var_path.values())))

src/plaid/storage/hf_datasets/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from collections.abc import Iterable, Mapping
44
from pathlib import Path
5-
from typing import Any, Optional, Union
5+
from typing import Any, Callable, Optional, Union
66

77
import numpy as np
88
from datasets import Dataset, IterableDatasetDict
@@ -65,7 +65,9 @@ def generate_to_disk(
6565
gen_kwargs: Optional[dict[str, dict[str, list]]] = None,
6666
num_proc: int = 1,
6767
verbose: bool = False,
68+
worker_initializer: Optional[Callable[[], None]] = None,
6869
) -> None:
70+
_ = worker_initializer
6971
return generate_datasetdict_to_disk(
7072
output_folder=output_folder,
7173
generators=generators,

src/plaid/storage/writer.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ def save_to_disk(
126126
verbose: bool = False,
127127
overwrite: bool = False,
128128
sample_callback: Optional[SampleCallback] = None,
129+
worker_initializer: Optional[Callable[[], None]] = None,
129130
) -> None:
130131
"""Save a PLAID dataset to local disk using the specified backend.
131132
@@ -193,6 +194,9 @@ def sample_constructor(file_path):
193194
sample_callback: Optional callback, available for the ``'cgns'`` backend,
194195
invoked with the written sample and its context. In parallel mode,
195196
it must be picklable and process-safe.
197+
worker_initializer: Optional callable executed once when each worker
198+
process starts. It must be picklable when using the ``spawn`` start
199+
method.
196200
"""
197201
assert backend in available_backends(), (
198202
f"backend {backend} not among available ones: {available_backends()}"
@@ -244,7 +248,11 @@ def sample_constructor(file_path):
244248
else:
245249
flat_cst, variable_schema, constant_schema, num_samples, cgns_types = (
246250
preprocess(
247-
generators, gen_kwargs=gen_kwargs, num_proc=num_proc, verbose=verbose
251+
generators,
252+
gen_kwargs=gen_kwargs,
253+
num_proc=num_proc,
254+
verbose=verbose,
255+
worker_initializer=worker_initializer,
248256
)
249257
)
250258
save_metadata_to_disk(
@@ -281,6 +289,7 @@ def sample_constructor(file_path):
281289
gen_kwargs=gen_kwargs,
282290
num_proc=num_proc,
283291
verbose=verbose,
292+
worker_initializer=worker_initializer,
284293
**backend_kwargs,
285294
)
286295

src/plaid/storage/zarr/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from collections.abc import Iterable, Mapping
44
from pathlib import Path
5-
from typing import Any, Optional, Union
5+
from typing import Any, Callable, Optional, Union
66

77
import numpy as np
88
import zarr
@@ -66,15 +66,19 @@ def generate_to_disk(
6666
gen_kwargs: Optional[dict[str, dict[str, list]]] = None,
6767
num_proc: int = 1,
6868
verbose: bool = False,
69+
worker_initializer: Optional[Callable[[], None]] = None,
6970
) -> Any:
70-
return generate_datasetdict_to_disk(
71+
kwargs = dict(
7172
output_folder=output_folder,
7273
generators=generators,
7374
variable_schema=variable_schema,
7475
gen_kwargs=gen_kwargs,
7576
num_proc=num_proc,
7677
verbose=verbose,
7778
)
79+
if worker_initializer is not None:
80+
kwargs["worker_initializer"] = worker_initializer
81+
return generate_datasetdict_to_disk(**kwargs)
7882

7983
@staticmethod
8084
def push_local_to_hub(

src/plaid/storage/zarr/writer.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ def generate_datasetdict_to_disk(
157157
gen_kwargs: Optional[dict[str, dict[str, Any]]] = None,
158158
num_proc: int = 1,
159159
verbose: bool = False,
160+
worker_initializer: Optional[Callable[[], None]] = None,
160161
) -> None:
161162
"""Generates and saves a dataset dictionary to disk in Zarr format.
162163
@@ -180,6 +181,9 @@ def generate_datasetdict_to_disk(
180181
Defaults to 1 (sequential). Must be > 1 only when gen_kwargs is provided.
181182
verbose (bool, optional): Whether to display progress bars during processing.
182183
Defaults to False.
184+
worker_initializer (callable, optional): Callable executed once when each
185+
worker process starts. It must be picklable when using the ``spawn``
186+
start method.
183187
184188
Returns:
185189
None: This function does not return a value; it writes the dataset directly
@@ -221,7 +225,10 @@ def generate_datasetdict_to_disk(
221225
# If your platform/library stack is sensitive to fork, use spawn:
222226
# ctx = mp.get_context("spawn")
223227
# with ctx.Pool(processes=num_proc) as pool:
224-
with mp.Pool(processes=num_proc) as pool:
228+
with mp.Pool(
229+
processes=num_proc,
230+
initializer=worker_initializer,
231+
) as pool:
225232
with tqdm(
226233
total=total_samples,
227234
desc=f"Writing {split_name} split",

0 commit comments

Comments
 (0)