【问题标题】:Dask and Numba - How to use map partitions efficiently?Dask 和 Numba - 如何有效地使用地图分区?
【发布时间】:2019-01-10 17:15:36
【问题描述】:

我正在尝试加快我的代码速度并提高我对 Dask 和 Numba 的理解,我确实尝试在我创建的一些示例中同时使用这两种方法,但没有任何改进,我不明白为什么。

我必须说我使用的是具有四核的笔记本电脑,因此改进可能不会很大,但它应该在那里。

更准确地说是在 Windows 10 笔记本电脑上,使用 Python 3.7 并在 conda 环境中使用 Numba 和 Dask。

这是我的代码:

import numpy as np
import pandas as pd
from numba import jit
import dask.dataframe as dd

data = np.random.randint(-10, 10, (10**8, 3))
df = pd.DataFrame(data=data, columns=["A", "B", "C"], index=None)
df["F"] = np.random.choice(["apple", "banana", "orange", 
                            "pear","grape","lime","citrus","peach"],10**8)

正如您所见,这是一个相当大的数据帧内存,这是我检查 Dask 是否代表改进的方法。在较小的数据帧(

ddf = dd.from_pandas(df,npartitions=12)

@jit
def remove_special_char_with_numba(x):
    return x.replace('r','')

这是一个玩具示例,我尝试从特定列中删除字符串,与原版 Pandas 相比,Numba 确实加快了代码速度,但不支持字符串,因此我无法修改 替换或使用 nopython 模式。 现在:

%%timeit
remove_special_char_with_numba(df["F"])

输出:

每个循环 58.9 秒 ± 9.51 秒(7 次运行的平均值 ± 标准偏差,每次 1 个循环)

接下来,我对以下内容的理解是,Dask 将我的数据帧分成不同的块/分区,并且它将独立地将函数应用于每个分离的块。据我了解,它有四个核心,应该可以加快进程。

%%timeit
ddf["F"].map_partitions(remove_special_char_with_numba).compute()

输出:

每个循环 45.9 s ± 10.5 s(平均值 ± 标准偏差,7 次运行,每次 1 个循环)

现在我不想贪心,但改进不应该比这更大吗?我是不是做错了什么?

谢谢

【问题讨论】:

    标签: python python-3.x dask numba


    【解决方案1】:

    这个结果应该不会让您太惊讶。显然,您正在默认线程调度程序上运行。

    这意味着每个字符串操作都必须获得单个 python GIL 才能发生,无论是在 dask 控制的工作线程中都是如此。对于 numba-jit 版本的操作仍然如此,因为您无法在 no-python 模式下运行此函数。如果它在 no-python 模式下,它将释放 GIL,并且完整的字符串支持将进入 numba。

    您可能能够使用具有多个进程的分布式调度程序来获得更好的加速,尽管您会承受在进程之间发送数据的成本,因此如何生成数据以及您将所有当你 compute() 时,结果进入主会话。

    【讨论】:

    • 我没有找到使用 nopython 的方法,而且我似乎也不可能进行字符串操作。我确实尝试了一些布尔转换,但用另一个替换特定字符串证明是有问题的。有没有办法以更好的方式计算它,以便我得到更好的改进?我不太了解 compute 方法的参数,所以我保留了它。有没有什么地方可以读到关于 Dask 的稍微笨拙的版本?谢谢
    • 1) 试验分布式调度器,改变进程数; 2)numba(还)不能帮助你,但如果你真的想的话,你可以写 cython; 3)与往常一样,您最好对分区中的数据执行 s8 操作,而不是将所有结果收集到 pandas 数据框
    • 好的,所以我应该将该函数应用于每个分区,并且只有在完成后才将其返回到 pandas 数据框?我的理解是错误的吗,这是我在上面的代码中所做的吗?好的,我会查看调度程序,看看是否还有更多工作要做
    • 简短的故事:如果某些东西与 pandas in-memory 配合得很好,那么你将很难击败它。避免 GIL 会带来沟通成本或转向不同的技术。这超出了这里的答案。
    • 好吧,我会继续玩,看看它的结果。感谢您的帮助!