使用 joblib 比单线程循环慢

Using joblib is slower than single thread loop

提问人:vitamin Cho 提问时间:11/17/2023 最后编辑:halfervitamin Cho 更新时间:11/17/2023 访问量:34

问:

from tqdm import tqdm
from joblib import Parallel, delayed
import numpy as np
import time

def func(x,a,b,c):
    """x3+ax2+bx+c"""
    return x**3+a*x**2+b*x+c

def func_prime(x,a,b):
    """3x2+2ax+b"""
    return 3*x**2+2*a*x+b

def check(i):
    a,b,c = i
    if func_prime(-1/4, a,b) != -1/4:
        return False
    if func_prime(1/4,a,b) >=0:
        return False
    for i in range(-300,300):
        if func(i-1, a,b,c)*func(i+1,a,b,c)<0:
            return False
    return a,b,c

def gen():
    a=np.arange(-1, 1, 1/128)
    b=np.arange(-1, 1, 1/128)
    c=np.arange(-1, 1, 1/128)
    for i_a in a:
        for i_b in b:
            for i_c in c:
                yield i_a, i_b, i_c

# single thread. it spend 11 seconds. 
result = set()
for i in tqdm(gen()):
    result.update([check(i)])

# using joblib. it spend 313 seconds. 
start_time = time.time()
_ = Parallel(n_jobs=10)(delayed(check)(i) for i in gen())
end_time = time.time()
print(end_time - start_time)

为了好玩,我试图解决一个数学测验,解决方案是“fx=x3-0.375x2-0.625x + 0”。

我的代码测试了所有值的组合,所以我认为并行编程可以加快速度。但事实并非如此,它比使用单个线程慢得多。

我的问题:

  1. 为什么多线程速度较慢?
  2. 如何比单线程更快地修复它?
  3. 提早停止。如果我找到解决方案,请尽快退出。我该如何实现?
Python 多线程 joblib

评论


答:

1赞 J_H 11/17/2023 #1

tl;dr:你在错误的地方迭代。


gen()产生许多值(三元组), 这些序列化并向下发送到工作子进程。

def check(i):
    a, b, c = i
    ...
    for i in range(-300, 300):

首先,第二个是错误的标识符,它应该是. 从元组开始,然后切换到标量真是太奇怪了, 避免这样做。ix

其次,循环可能会提前退出。 现在,如果我们通常进行 600 次迭代, 这可能是一种明智的亲子工作平衡。 但我感觉到我们花了很多钱 对这 3 元组进行时间序列化,发送它们 沿着管道,快速反序列化它们 在达到六百之前很久就提前退出。for

你已经嵌套了 a、b、c 循环和 10 个内核。 我建议父级遍历值, 并让孩子担心迭代。 这样一来,您就花费了更大比例的 CPU 周期 在评估上比在序列化/反序列化上。ab, cfunc


单独问题:

    if func_prime(-0.25, a, b) != -0.25:

通常不建议测试浮点数的完全相等性 (或者在这种情况下,不平等)。 比较时, 更喜欢计算是否小于一些小的 epsilon (或者在本例中,大于 ε )。x == yabs(x - y)

我们有一个特例,在这里, 2 的幂的倒数, 所以IEEE-754可以准确地表示 感兴趣的数量。 但总的来说,你应该发展 一些健康程度的偏执狂 关于 FP 舍入问题。