下面是multiprocessing.Pool对multiprocessing.pool.ThreadPool和顺序版本的一些测试,我想知道为什么multiprocessing.pool.ThreadPool版本比顺序版本慢?
multiprocessing.Pool确实更快吗?因为它使用进程(即没有GIL)和multiprocessing.pool.ThreadPool使用线程(即GIL),尽管包的名称是multiprocessing。
import time
def test_1(job_list):
from multiprocessing import Pool
print('-' * 60)
print("Pool map")
start = time.time()
p = Pool(8)
s = sum(p.map(sum, job_list))
print('time:', time.time() - start)
def test_2(job_list):
print('-' * 60)
print("Sequential map")
start = time.time()
s = sum(map(sum, job_list))
print('time:', time.time() - start)
def test_3(job_list):
from multiprocessing.pool import ThreadPool
print('-' * 60)
print("ThreadPool map")
start = time.time()
p = ThreadPool(8)
s = sum(p.map(sum, job_list))
print('time:', time.time() - start)
if __name__ == '__main__':
job_list = [range(10000000)]*128
test_1(job_list)
test_2(job_list)
test_3(job_list)输出:
------------------------------------------------------------
Pool map
time: 3.4112906455993652
------------------------------------------------------------
Sequential map
time: 23.626681804656982
------------------------------------------------------------
ThreadPool map
time: 76.83279991149902发布于 2022-01-13 17:57:03
您的任务完全是CPU约束的(没有I/O上的阻塞),并且没有使用任何扩展代码来手动释放GIL来执行大量的数字处理,而不需要Python级别的引用计数对象(例如,hashlib散列大型输入、大型数组numpy计算等)。因此,GIL的定义阻止您从代码中提取任何并行性;只有一个线程可以同时保存GIL并执行Python字节码,而您的执行速度较慢,因为:
。
简而言之,是的,ThreadPool does what it says on the tin:它提供与Pool相同的API,但是由线程支持,而不是工作进程,因此不能避免GIL限制和开销。直到最近,它才被直接记录下来;相反,它是由multiprocessing.dummy文档间接记录的,这些文档更明确地说明了提供multiprocessing API,但是由线程支持,而不是进程(您使用它作为multiprocessing.dummy.Pool,实际上没有包含“线程”这个词)。
我将注意到,您的测试使Pool看起来比正常情况更好。通常,Pool在这样的任务中做得不好(大量数据,相对于数据大小计算很少),因为序列化数据并将其发送到子进程的成本超过了并行工作带来的微小收益。但是,由于您的“大数据”是由range对象表示的(这些对象以较低的成本序列化,作为对range类的引用和用于重构它的参数),所以很少有数据传输到和从工作人员之间传输。如果您使用真正的数据(实现了list的int),Pool的好处就会急剧下降。例如,只需将job_list的定义更改为:
job_list = [[*range(10000000)]] * 128我的机器上的Pool时间(未经修改的Pool情况需要3.11秒)跃升到8.11秒。甚至这也是一个谎言,因为pickle序列化代码识别重复重复的相同list,并且只序列化内部list一次,然后快速地“查看第一个list”代码来重复它。我告诉你什么用途:
job_list = [[*range(10000000)] for _ in range(128)]对运行时进行了处理,但我几乎让我的机器崩溃,只是试图运行这一行(创建said list of lists需要大约46 GB的内存,在父进程中支付一次,然后在子进程中再支付一次);可以这么说,Pool将非常糟糕,特别是在数据只适合RAM一次、但不是两次的情况下。
https://stackoverflow.com/questions/70700809
复制相似问题