Skip to content

Commit 31eaebb

Browse files
authored
Merge pull request #206 from cgat-developers/AC-pipes
Ac pipes
2 parents 77f7651 + 797547e commit 31eaebb

6 files changed

Lines changed: 80 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Version 0.6.20
2+
3+
- Fix pipeline parallelism: pass `multiprocess` to `ruffus.pipeline_run()` so multiple jobs run in parallel again
4+
15
# Version 0.6.19
26

37
- Update GitHub Actions workflows to use latest action versions

cgatcore/pipeline/control.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444

4545
import cgatcore.experiment as E
4646
import cgatcore.iotools as iotools
47-
from cgatcore.pipeline.parameters import input_validation, get_params, get_parameters
47+
from cgatcore.pipeline.parameters import (
48+
input_validation, get_params, get_parameters, write_params_init_file)
4849
from cgatcore.experiment import get_header, MultiLineFormatter
4950
from cgatcore.pipeline.utils import get_caller, get_caller_locals, is_test
5051
from cgatcore.pipeline.execution import execute, start_session, \
@@ -1251,6 +1252,9 @@ def initialize(argv=None, caller=None, defaults=None, optparse=True, **kwargs):
12511252
logger.info("changing directory to {}".format(work_dir))
12521253
os.chdir(work_dir)
12531254

1255+
# Write params snapshot for spawned worker processes (multiprocess with spawn)
1256+
write_params_init_file(work_dir)
1257+
12541258
logger.info("pipeline has been initialized")
12551259

12561260
return args
@@ -1302,7 +1306,8 @@ def run_workflow(args, argv=None, pipeline=None):
13021306
logger=logger, verbose=args.loglevel, log_exceptions=args.log_exceptions,
13031307
exceptions_terminate_immediately=args.exceptions_terminate_immediately,
13041308
checksum_level=args.ruffus_checksums_level, pipeline=pipeline,
1305-
one_second_per_job=False
1309+
one_second_per_job=False,
1310+
multiprocess=args.multiprocess
13061311
)
13071312

13081313
except ruffus.ruffus_exceptions.RethrownJobError as ex:

cgatcore/pipeline/parameters.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"""
88

99
import collections
10+
import json
1011
import os
1112
import sys
1213
import platform
@@ -561,8 +562,58 @@ def check_parameter(param):
561562
raise ValueError("need `%s` to be set" % param)
562563

563564

565+
def _get_serializable_params():
566+
"""Return a dict of PARAMS entries that are JSON-serializable (for worker init file)."""
567+
out = {}
568+
for k, v in PARAMS.items():
569+
try:
570+
json.dumps(v)
571+
out[k] = v
572+
except (TypeError, ValueError):
573+
pass
574+
return out
575+
576+
577+
def _load_params_in_worker():
578+
"""Load PARAMS from init file in a spawned worker process (multiprocess spawn)."""
579+
global HAVE_INITIALIZED
580+
path = os.environ.get("CGAT_PARAMS_INIT_FILE")
581+
if not path or not os.path.exists(path):
582+
return
583+
try:
584+
with open(path, "rt", encoding="utf8") as f:
585+
loaded = json.load(f)
586+
PARAMS.update(loaded)
587+
HAVE_INITIALIZED = True
588+
except Exception:
589+
pass
590+
591+
592+
def write_params_init_file(work_dir):
593+
"""Write a JSON snapshot of PARAMS for spawned worker processes.
594+
Call from the main process after initialize(); set CGAT_PARAMS_INIT_FILE in env.
595+
"""
596+
if not HAVE_INITIALIZED:
597+
return
598+
try:
599+
data = _get_serializable_params()
600+
path = os.path.join(os.path.abspath(work_dir), "cgat_params_init_{}.json".format(os.getpid()))
601+
with open(path, "wt", encoding="utf8") as f:
602+
json.dump(data, f, indent=0)
603+
os.environ["CGAT_PARAMS_INIT_FILE"] = path
604+
except Exception:
605+
pass
606+
607+
564608
def get_params():
565609
"""return handle to global parameter dictionary"""
610+
if not HAVE_INITIALIZED:
611+
try:
612+
import multiprocessing
613+
if multiprocessing.current_process().name != "MainProcess":
614+
_load_params_in_worker()
615+
except ImportError:
616+
pass
566617
return PARAMS
567618

568619

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "cgatcore"
7-
version = "0.6.19"
7+
version = "0.6.20"
88
description = "cgatcore: the Computational Genomics Analysis Toolkit"
99
authors = [
1010
{ name = "Adam Cribbs", email = "adam.cribbs@ndorms.ox.ac.uk" }

tests/template.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Default parameters for template_pipeline tests
2+
min_value: 0.0
3+
num_samples: 1000
4+
mu: 0.0
5+
sigma: 1.0

tests/template_pipeline.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,18 @@ def main(argv=None):
7676
if argv is None:
7777
argv = sys.argv
7878

79-
# Get the args first
80-
args = P.initialize(argv, config_file="template.yml")
81-
82-
# Then use them in the defaults dictionary
83-
P.get_params().update({
84-
"min_value": 0.0,
85-
"num_samples": 1000,
86-
"mu": 0.0,
87-
"sigma": 1.0,
88-
"to_cluster": not args.without_cluster # Now args is defined
89-
})
79+
# Pass defaults so params are set before any parallel task runs (workers need them too)
80+
args = P.initialize(
81+
argv,
82+
config_file="template.yml",
83+
defaults={
84+
"min_value": 0.0,
85+
"num_samples": 1000,
86+
"mu": 0.0,
87+
"sigma": 1.0,
88+
},
89+
)
90+
P.get_params().update({"to_cluster": not args.without_cluster})
9091

9192
pipeline = ruffus.Pipeline("template_pipeline")
9293

0 commit comments

Comments
 (0)