Dask分布式代码运行远慢于串行执行,求问题定位
我在配备4核CPU的Linux桌面运行以下独立Python脚本,使用Dask分布式(Client+delayed+processes调度)计算位温,当前耗时0.735秒,目的是通过多进程规避GIL限制。
Dask分布式代码
import numpy as np import dask from dask import delayed from dask.distributed import Client import time def main(): if __name__ == "__main__": client = Client() tmp,pres = setUpData() startTime = time.time() executeCalc(tmp,pres) stopTime = time.time() print(stopTime-startTime) def setUpData(): temperature = 273 + 20 * np.random.random([4,17,73,144]) pres = ["1000","925","850","700","600","500","400","300","250","200","150","100","70","50","30","20","10"] level = np.array(pres) level = level.astype(float)*100 return temperature,level def executeCalc(tmp,pres): potempList = [] for i in range (0,tmp.shape[0]): tmpInstant = tmp[i,:,:,:] potempList.append(delayed(pot)(tmpInstant,pres)) results = dask.compute(potempList,scheduler='processes',num_workers=4) def pot(tmp,pres): potemp = np.zeros((17,73,144)) potemp = tmp * (100000./pres[:,None,None]) return potemp main()
串行执行代码(耗时仅0.0024秒)
仅修改了executeCalc函数:
def executeCalc(tmp,pres): potempList = [] for i in range (0,tmp.shape[0]): tmpInstant = tmp[i,:,:,:] potemp = pot(tmpInstant,pres)
疑问:我哪里出错了?至少对于这样的小数据量,两者执行时间应该相近才对。
核心问题:开销远超计算本身
你的Dask代码耗时高,本质是分布式/多进程的额外开销完全覆盖了计算收益,具体问题点如下:
分布式Client启动开销:
Client()会创建本地分布式集群(调度器+工作进程),这个启动过程本身就需要几百毫秒,而你的计算任务本身仅需0.0024秒,启动开销直接主导了总耗时。多进程调度的冗余开销:即使不用分布式Client,
processes调度器也会涉及进程创建、数据序列化/反序列化、进程间数据传输的开销。你的计算是简单的numpy数组乘法,属于轻量任务,这些额外开销远大于多进程带来的收益。代码结构错误:
main()函数内嵌套if __name__ == "__main__"是不良写法,虽然Linux下fork机制影响较小,但会导致子进程重复执行不必要的逻辑,增加潜在开销。调度器参数冲突:启动
Client后又指定scheduler='processes',相当于混用两种调度方式,额外增加了调度混乱和开销。
优化建议
移除分布式Client:小数据量轻量计算完全不需要分布式集群,甚至多进程都没必要——numpy底层依赖BLAS/MKL等库,已经自动启用多线程并行,GIL在数值计算时会被释放,多进程反而因数据拷贝变慢。
修正代码结构:将
if __name__ == "__main__"移至全局作用域,避免嵌套:if __name__ == "__main__": tmp,pres = setUpData() startTime = time.time() executeCalc(tmp,pres) stopTime = time.time() print(stopTime-startTime)评估是否需要Dask:如果你的实际业务是大尺度循环而非numpy向量化操作,可尝试用Dask本地多进程,但需确保计算任务足够重,能抵消调度开销。对于当前场景,直接用串行numpy代码就是最优解。
内容的提问来源于stack exchange,提问作者gansub

