【发布时间】:2022-10-18 09:11:43
【问题描述】:
我正在尝试将大文件拆分为较小的部分。我将首先从大文件中读取所有数据,然后使用多处理将它们写入不同的较小数据文件。
这里是方法一,这里是使用multiprocessing.Process来初始化一个进程,效果很好
def split_data_with_process(filepath, chunk_num):
def write(write_data, index, name, prev_path, suffix):
print("enter")
start_time = time.time()
with open(prev_path + f"/{name}_{index}.{suffix}", "w", encoding="utf-8") as f:
f.writelines(write_data)
print(time.time()-start_time)
prev_path, filename = filepath.rsplit("/", maxsplit=1)
name, suffix = filename.split(".")
with open(filepath, "r", encoding="utf-8") as f:
totalList = f.readlines()
chunksize = math.ceil(len(totalList) / chunk_num)
data = [(totalList[start:start + chunksize], index) for index, start in
enumerate(range(0, len(totalList), chunksize))]
tasks = []
start_time = time.time()
for each in data:
task = multiprocessing.Process(target=write, args=(each[0], each[1], name, prev_path, suffix))
task.start()
tasks.append(task)
for each in tasks:
each.join()
end_time = time.time()
print(end_time - start_time)
输出是
enter
enter
enter
enter
enter
7.192562818527222
8.827389001846313
9.067991018295288
9.476916313171387
7.729929208755493
15.109729290008545
然后我尝试用ProcessPoolExecutor重写代码,代码就像
def write(input):
list, index, prev_path, name, suffix = input
print("enter")
start_time = time.time()
with open(prev_path + f"/{name}_{index}.{suffix}", "w", encoding="utf-8") as f:
f.writelines(list)
print(time.time() - start_time)
return len(list)
def split_data_with_process_2(filepath, chunk_num):
prev_path, filename = filepath.rsplit("/", maxsplit=1)
name, suffix = filename.split(".")
with open(filepath, "r", encoding="utf-8") as f:
totalList = f.readlines()
chunksize = math.ceil(len(totalList) / chunk_num)
data = [(totalList[start:start + chunksize], index, prev_path, name, suffix) for index, start in
enumerate(range(0, len(totalList), chunksize))]
start_time = time.time()
with ProcessPoolExecutor(max_workers=chunk_num) as pool:
result = pool.map(write, data)
print(sum(result))
end_time = time.time()
print(end_time - start_time)
第二种方式比第一种方式需要更长的时间。我发现看起来不同的进程是串行工作而不是并行工作。输出是
enter
3.416102170944214
enter
3.3221476078033447
enter
3.198657989501953
enter
3.453885316848755
enter
3.261833429336548
16149274
42.55615472793579
那么这里的问题是什么?
【问题讨论】:
-
我不确定,但我认为这是因为 ProcessPoolExecutor 动态设置了进程数。您的系统上有多少个 CPU?
-
此外,ProcessPoolExecutor 有很多开销,并且您主要执行 I/O 有界操作,这对多处理没有强烈的需求。也许您希望使用async file i/o 获得更好的性能?
-
尚不清楚甚至多线程或异步是否会提高性能。您仍然会同时写入多个文件,并且您的驱动器(除非它是固态驱动器)可能会因此在您正在写入的文件之间来回移动更多的头部。
-
是的,我也怀疑多处理是无用的,因为它主要是 I/O 受限的,但我的测试表明,与仅在单个进程中完成所有事情相比,它确实降低了多处理的时间成本。我还尝试了多线程版本,它比单线程方法花费更多时间。 @Booboo
-
我正在使用 [GCC 10.3.0] Python 3.9.12 在 linux 上运行代码。根据 top 命令,CPU 的数量是 44,我在上面的代码中设置了 max_workers=5。我感到奇怪的是,当我使用 ProcessPoolExecutor @tturbo 时,看起来不同的进程是串行工作而不是并行工作
标签: python multiprocessing python-multiprocessing process-pool