如何在dask分布式中组合任务

时间:2018-10-21 17:56:33

标签: python dask joblib dask-distributed

我正在尝试在一个线程分布的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)

1 个答案:

答案 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=关键字来控制每个作业的进程。

您拥有的任务多于流程。