【问题标题】:No gain from multiple threads when using ThreadPoolExecutor使用 ThreadPoolExecutor 时没有从多个线程中获得收益
【发布时间】:2019-09-04 05:27:02
【问题描述】:

我正在尝试模拟一些流程以获得一些统计数据。我决定使用多个线程编写模拟程序,因为每个测试运行都是独立的。

这意味着如果我需要执行例如1000 次测试运行,那么应该可以有 4 个线程(每个执行 250 次测试运行)。

在执行此操作时,我发现添加多个线程不会减少模拟时间。

我有 4 个物理内核的 Windows 10 笔记本电脑。

我编写了一个简单的程序来显示我正在谈论的行为。

from concurrent.futures import ThreadPoolExecutor
import time
import psutil
import random


def runScenario():
    d = dict()
    for i in range(0, 10000):
        rval = random.random()
        if rval in d:
            d[rval] += 1
        else:
            d[rval] = 1
    return len(d)    

def runScenarioMultipleTimesSingleThread(taskId, numOfCycles):
    print('starting thread {}, numOfCycles is {}'.format(taskId, numOfCycles))

    sum = 0
    for i in range(numOfCycles):
        sum += runScenario()

    print('thread {} finished'.format(taskId))

    return sum

def modelAvg(numOfCycles, numThreads):

    pool = ThreadPoolExecutor(max_workers=numThreads)

    cyclesPerThread = int(numOfCycles / numThreads)
    numOfCycles = cyclesPerThread * numThreads

    futures = list()
    for i in range(numThreads):
        future = pool.submit(runScenarioMultipleTimesSingleThread, i, cyclesPerThread)
        futures.append(future)

    sum = 0
    for future in futures:
        sum += future.result()

    return sum / numOfCycles


def main():
    p = psutil.Process()
    print('cpus:{}, affinity{}'.format(psutil.cpu_count(), p.cpu_affinity() ))

    start = time.time()
    modelAvg( numOfCycles = 10000, numThreads = 4)
    end = time.time()

    print('simulation took {}'.format(end - start))

if __name__ == '__main__':
    main()

这些是结果:

一个线程:

cpus:8, affinity[0, 1, 2, 3, 4, 5, 6, 7]
starting thread 0, numOfCycles is 10000
thread 0 finished
simulation took 23.542529582977295

四个线程:

cpus:8, affinity[0, 1, 2, 3, 4, 5, 6, 7]
starting thread 0, numOfCycles is 2500
starting thread 1, numOfCycles is 2500
starting thread 2, numOfCycles is 2500
starting thread 3, numOfCycles is 2500
thread 1 finished
thread 2 finished
thread 0 finished
thread 3 finished
simulation took 23.508538484573364

我希望在使用 4 线程时,模拟时间理想情况下应该缩短 4 倍,当然它不应该相同。

【问题讨论】:

标签: python multithreading


【解决方案1】:

当您使用 cPython 时,通过跨线程分配计算负载不会获得显着的加速。这是因为 cPython 中的内存访问是使用Python GIL mechanism(全局解释器锁)序列化的。例如,我在处理文本时遇到过这种情况。

在这种情况下,如果您监控您的 CPU,您可能会发现您的进程没有充分利用其中的 4 个,每个只有 25%。

您可以使用 MultiProcessing 真正将负载分散到 CPU。

当您的线程受 IO 限制(相对于 CPU 限制)时,线程仍然可以在 Python 中提供性能改进。

【讨论】:

  • 非常感谢您的解释。 ProcessPoolExecutor 确实符合我的预期。
猜你喜欢
  • 1970-01-01
  • 2013-01-23
  • 1970-01-01
  • 1970-01-01
  • 2020-02-26
  • 1970-01-01
  • 1970-01-01
  • 2020-07-02
  • 1970-01-01
相关资源
最近更新 更多