diff --git a/Orange/evaluation/testing.py b/Orange/evaluation/testing.py index ed063ba2950..46667314267 100644 --- a/Orange/evaluation/testing.py +++ b/Orange/evaluation/testing.py @@ -1,3 +1,4 @@ +import sys import multiprocessing as mp from itertools import product from threading import Thread @@ -314,6 +315,12 @@ def _mp_worker(train_data, test_data, test_i, fold_i, learner_i, learner, queue) return fold_i, learner_i, test_i, model, failed, predicted, probs +def _mp_context(): + # Workaround for locks on Macintosh + # https://pythonhosted.org/joblib/parallel.html#bad-interaction-of-multiprocessing-and-third-party-libraries + return mp.get_context('forkserver' if sys.platform == 'darwin' else None) + + class CrossValidation(Results): """ K-fold cross validation. @@ -381,7 +388,8 @@ def __init__(self, data, learners, k=10, random_state=0, store_data=False, # generators are concerned. I'm stumped. product(data_splits, enumerate(learners))) - with joblib.Parallel(n_jobs=n_jobs) as parallel: + ctx = _mp_context() + with joblib.Parallel(n_jobs=n_jobs, backend=ctx) as parallel: tasks = (joblib.delayed(_mp_worker)(*tup) for tup in args) thread = Thread(target=lambda: results.append(parallel(tasks))) thread.start() @@ -446,7 +454,8 @@ def data_splits(): for (fold_i, test_i, train, test) in data_splits() for (learner_i, learner) in enumerate(learners)) - with joblib.Parallel(n_jobs=n_jobs) as parallel: + ctx = _mp_context() + with joblib.Parallel(n_jobs=n_jobs, backend=ctx) as parallel: tasks = (joblib.delayed(_mp_worker)(*tup) for tup in args) thread = Thread(target=lambda: results.append(parallel(tasks))) thread.start() @@ -498,7 +507,8 @@ def data_splits(): for (fold_i, test_i, train, test) in data_splits() for (learner_i, learner) in enumerate(learners)) - with joblib.Parallel(n_jobs=n_jobs) as parallel: + ctx = _mp_context() + with joblib.Parallel(n_jobs=n_jobs, backend=ctx) as parallel: tasks = (joblib.delayed(_mp_worker)(*tup) for tup in args) thread = Thread(target=lambda: results.append(parallel(tasks))) thread.start() @@ -565,7 +575,8 @@ def data_splits(): for (fold_i, test_i, train, test), (learner_i, learner) in product(data_splits(), enumerate(learners))) - with joblib.Parallel(n_jobs=n_jobs) as parallel: + ctx = _mp_context() + with joblib.Parallel(n_jobs=n_jobs, backend=ctx) as parallel: tasks = (joblib.delayed(_mp_worker)(*tup) for tup in args) thread = Thread(target=lambda: results.append(parallel(tasks))) thread.start() @@ -634,7 +645,8 @@ def data_splits(): for (fold_i, test_i, train, test) in data_splits() for (learner_i, learner) in enumerate(learners)) - with joblib.Parallel(n_jobs=n_jobs) as parallel: + ctx = _mp_context() + with joblib.Parallel(n_jobs=n_jobs, backend=ctx) as parallel: tasks = (joblib.delayed(_mp_worker)(*tup) for tup in args) thread = Thread(target=lambda: results.append(parallel(tasks))) thread.start()