代码之家  ›  专栏  ›  技术社区  ›  madmatrix

Dask图书馆的延迟装饰师-结果适得其反

  •  0
  • madmatrix  · 技术社区  · 1 年前

    尝试学习如何使用dask库并点击链接 https://www.machinelearningplus.com/python/dask-tutorial/

    使用dask延迟装饰器的代码

    import time
    import dask
    from dask import delayed
    
    @delayed
    def square(x):
        return x*x
    
    @delayed
    def double(x):
        return x*2
    
    @delayed
    def add(x, y):
        return x + y
    
    @delayed
    def sum(output):
        sum = 0
        for i in output:
            sum += i
    
        return sum
    
    t1 = time.time()
    
    # For loop that calls the above functions for each data
    output = []
    for i in range(99999):
        a = square(i)
        b = double(i)
        c = add(a, b)
        output.append(c)
    
    total = dask.delayed(sum)(output)
    print(total)
    
    print("Elapsed time: ", time.time() - t1)
    

    运行时间: ~8.46秒

    没有任何dask/decorator的普通代码

    import time
    
    def square(x):
        return x*x
    
    def double(x):
        return x*2
    
    def add(x, y):
        return x + y
    
    def sum(output):
        sum = 0
        for i in output:
            sum += i
    
        return sum
    
    t1 = time.time()
    
    # For loop that calls the above functions for each data
    output = []
    for i in range(99999):
        a = square(i)
        b = double(i)
        c = add(a, b)
        output.append(c)
    
    total = sum(output)
    print(total)
    
    print("Elapsed time: ", time.time() - t1)
    

    运行时间: 约0.043秒

    两种代码变体都在上执行,

    Windows计算机

    4芯

    8个逻辑核心

    Python 3.11.0

    dask版本2023.6.0

    代码不应该与 @延迟的 与其他以串行顺序执行函数的变体相比,来自dask的decorator执行得更好?通过任务图识别要并行或串行执行的任务是否会产生开销,从而适得其反?想知道迭代次数是否太少,无法实现dask库的好处,尝试增加值,但它仍然是一样的。

    有人能澄清一下吗?

    0 回复  |  直到 1 年前
        1
  •  -1
  •   mdurant    1 年前

    通过任务图识别要并行或串行执行的任务是否会产生开销,从而适得其反

    是的,定义执行图和执行每个任务都是有成本的。至少,这涉及到切换线程和检查每个任务的完成情况。在实践中,还有其他与决定下一步要做的任务和将结果拼接在一起相关的成本。因为您的python函数将在<100ns时,dask的开销是显著的。

    Dask示例不计算任何内容,而仅创建延迟对象的图。您应该调用compute()来计算总数。

    这是对的。对于本例,创建和存储任务以供以后执行的成本高于运行任务的成本。

    In [4]: %%timeit
       ...: @delayed
       ...: def add(x, y):
       ...:     return x + y
       ...:
    6.58 µs ± 26.4 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
    
    In [5]: def add(x, y):
       ...:     return x + y
       ...:
    
    In [6]: %timeit add(1, 1)
    59.6 ns ± 0.0345 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
    

    运行任务的开销取决于调度程序,但线程调度程序的开销为100秒,分布式调度程序的则接近1毫秒。

    那么,dask什么时候有用呢?

    • 如果您的函数运行时间较长
    • 如果您可以将许多小型计算批处理到与运行时相比开销较小的任务中

    还要注意的是,由于GIL的原因,您编写的代码在单个过程中不能很好地并行。在实践中,加速这些东西的真正方法是使用 numpy 早在您考虑dask等并行选项之前。