Caveat: Threading might not be parallel enough for you (see https://docs.python.org/2/library/threading.html note on the Global Interpreter Lock
) so you might have to use the multiprocessing
library instead (https://docs.python.org/2/library/multiprocessing.html).
...So I've cheated/been-lazy & used a thread/process neutral term "job". You'll need to pick either threading or multiprocessing for everywhere that I use "job".
def func1(c):
return a,b
def func2(c,x):
if condition:
a,b = func1(c)
x.append(a,b)
a_job = None
if (number_active_jobs() >= NUM_CPUS):
# do a and b sequentially
func2(a, x)
else:
a_job = fork_job(func2, a, x)
func2(b,x)
if a_job is not None:
join(a_job)
x = []
func2(c, x)
# all results are now in x (don't need y)
...that will be best if you need a,b pairs to finish together for some reason.
If you're willing to let the scheduler go nuts, you could "job" them all & then join
at the end:
def func1(c):
return a,b
def func2(c,x):
if condition:
a,b = func1(c)
x.append(a,b)
if (number_active_jobs() >= NUM_CPUS):
# do a and b sequentially
func2(a, x)
else:
all_jobs.append(fork_job(func2, a, x))
# TODO: the same job-or-sequential for func2(b,x)
all_jobs = []
x = []
func2(c, x)
for j in all_jobs:
join(j)
# all results are now in x (don't need y)
The NUM_CPUS check could be done with threading.activeCount()
instead of a full blown worker threa pool (python - how to get the numebr of active threads started by specific class?).
But with multiprocessing you'd have more work to do with JoinableQueue
and a fixed size Pool
of workers