【问题标题】:Why is the time a piece of the whole computaion (benchmking_f in this case) takes in parallel so much longer than the one in sequential approach?为什么整个计算的一部分(在这种情况下为benchmking_f)并行花费的时间比顺序方法中的时间长得多?
【发布时间】:2020-01-05 23:16:49
【问题描述】:

我正在尝试比较 Python 中的顺序计算和并行计算。

这是基准功能。

def benchmking_f(n=0):
    import time
    items = range(int(10**(6+n)))

    def f2(x):return x*x

    start = time.time()
    sum_squared = 0
    for i in items:
        sum_squared += f2(i)
    return time.time() - start

这个顺序计算

problem_size = 2

import time
start = time.time()
tlist = []
for i in range(5):
    tlist.append(benchmking_f(problem_size))
print('for loop took {}s'.format(time.time() - start))
print('each iterate took')
print(tlist)

完成这项工作大约需要 70 年代;每次迭代 [14.209498167037964、13.92169737815857、13.949078798294067、13.94432258605957、14.004642486572266]

这种并行方法

problem_size = 2

import itertools
import multiprocessing
start = time.time()
pool = multiprocessing.Pool(5)
tlist = list(pool.map(benchmking_f, itertools.repeat(problem_size, 5)))
print('pool.map took {}s'.format(time.time() - start))
print('each iterate took')
print(tlist)

耗时约 42.45 秒;每次迭代 [41.17476940155029、41.92032074928284、41.50966739654541、41.348535776138306、41.06284761428833]

问题

整个计算的一部分(本例中为 benchmking_f)顺序耗时约 14 秒,并行耗时 42.45 秒

这是为什么呢?

注意: 我不是在问总时间。我问的是整个计算的时间,它在 for 循环中进行一次迭代,并且并行处理一个进程/线程。

1-iter benchmking_f 接受。

【问题讨论】:

  • 但这并没有花更长的时间。 70 > 42.45。
  • @kindall 感谢您的提醒。我已经更新了。我不是在问总时间。我问的是整个计算的时间,它在 for 循环中进行一次迭代,并在一个进程/线程并行。

标签: python parallel-processing multiprocessing


【解决方案1】:

总时间减少:70 秒对 42 秒。

您的计算机同时处理 5 件事情,可能是循环方式。线程开销(上下文负载等)发生并且每个线程花费了更长的时间。然而,由于较长的线程并行运行,5 个线程在 42 秒内完成。

对于顺序,您的计算机正在处理相同的事情 5 次。每个线程都可以运行直到它完成而不会中断(因此,没有开销)。然而,所有这些都需要 70 秒才能完成。

【讨论】:

  • “线程”是指进程吗? multiprocessing 是一个使用类似于线程模块的 API 支持生成进程的包。
  • 是的,你们两个都是对的。 threading = 这里的进程,开销更突出(因为进程开销更大)。
  • @SethMMorton 在谈到线程时,操作系统级别和程序级别有什么区别?
  • @singularli 你可能会觉得这很有用:stackoverflow.com/q/3042717/1399279
【解决方案2】:

您有多少物理(非逻辑)核心?您正在尝试同时运行该函数的 5 个副本,该函数在运行时会占用一个内核的 100%,除非您至少有 5 个物理内核,否则它们将在周期内互相争斗.

我有 4 个物理内核,但也想将我的机器用于其他事情,所以将您的 Pool(5) 减少为 Pool(3)然后每次迭代的时间都差不多。

信封背面

假设您有一个任务在T 秒内占用 100% 的 CPU。如果您想同时运行该任务的S 副本,则总共需要T*S cpu-seconds。如果你有 C 完全免费的物理内核可以扔给它,最多 min(C, S) 内核可以同时在聚合上工作,所以大致需要的时间是:

T*S / min(C, S)

正如另一个回复所说,当您运行的进程多于内核时,操作系统会在进程中循环运行一段时间,从而使它们都花费大约相同的挂钟时间(在此期间,每个进程什么都不做,只是等待操作系统让它再次运行一段时间)。

我猜你有 2 个物理核心。对于您的示例,T 大约是 14 秒,S 是 5,所以如果您有 C=2 核心,则可以解决

14*5 / min(2, 5) = 14*5/2 = 35

秒。实际上,您看到的结果接近 41。开销占其中的一部分,但您的机器似乎同时也在做其他工作,因此您的测试运行没有得到 100% 的 2 个内核。

【讨论】:

  • 感谢您的回答。 “每次迭代计时”是否意味着 benchmking_f 在您的 3 个线程中的每一个中花费的时间?
  • 是的,在我的盒子上,Pool(3) 串行运行在 14 到 16 秒内给出了一个包含 5 个数字的列表,并行运行相同(尽管比串行运行稍大一点),使用Pool(4),每个在 15 到 18 秒内,反映我有 4 个物理内核,其他进程也需要周期(操作系统、两个打开标签页的浏览器等)。请记住,time.time() 测量挂钟时间!当一个 CPU 密集型进程没有 100% 的 CPU 不间断运行时,它的一些挂钟时间只是闲置等待操作系统让它再次运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-31
  • 2017-06-03
  • 2016-08-24
  • 2021-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多