我正在尝试在一个线程分布的dask集群中运行一个joblib并行循环(请参阅下面的原因),但是由于GIL锁,我无法获得任何加速。这是一个示例:
sarray.Add("@colDate," + idDate.SelectedValue)
单CPU任务平均需要3.5秒
def task(x):
""" Sample single-process task that takes between 2 and 5 seconds """
import time
import random
dt = random.uniform(2,5)
time.sleep(dt)
return x+dt
def composite_task(np=8):
""" Composite task that runs multiple single-process runs in parallel """
from functools import partial
from joblib import Parallel, delayed, parallel_backend
with parallel_backend('loky', n_jobs=np):
out=Parallel()(delayed(task)(i) for i in list(range(0, np)))
return out
Joblib可以正常工作,八项任务的时间不超过一个最长的任务
%timeit -n7 -r1 task(0)
3.61 s ± 0 ns per loop (mean ± std. dev. of 1 run, 7 loops each)
但是,当我尝试在具有8个线程的快捷LocalCluster中运行此代码时,却没有任何加速效果
%timeit -n1 -r1 composite_task(8)
5.03 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)
可能我误解了GIL的工作原理。请帮忙。 完整的笔记本可以在这里查看:
http://nbviewer.jupyter.org/gist/aeantipov/6d670e13cd503741e9ef5b0299719a8e
尝试此操作的原因是必须在32个cpus的大约50个节点上解决GK锁定的10k任务。创建具有50个工作人员* 32个线程而不是1600个工作人员的dask-jobqueue集群很容易。不幸的是,由于GIL已锁定,因此使用此示例http://matthewrocklin.com/blog/work/2018/06/26/dask-scaling-limits并不会大大提高运行50个工作线程的速度。
from dask.distributed import Client, LocalCluster
cluster = LocalCluster(n_workers=1, threads_per_worker=8)
client = Client(cluster)
%timeit -n1 -r1 client.submit(composite_task,8).result()
25.5 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)
答案 0 :(得分:0)
我只会使用dask-joblib解决方案
cluster = LocalCluster()
client = Client(cluster)
with joblib.parallel_backend('dask'):
out=Parallel()(delayed(task)(i) for i in range(0, np))
您对GIL的担忧不在这里适用。您的函数调用sleep,这会在执行期间释放GIL。如果您的实际功能是纯Python代码且未发布GIL,则建议您启动包含许多单线程进程的Dask集群。如果您使用的是dask-jobqueue,那么您想使用processes=
关键字来控制每个作业的进程。
您拥有的任务多于流程。