当批量处理特别大的文件时,为了节约时间,通常使用多进程、多线程的方式并行处理,本文主要展示带有返回结果的多进程、多线程python示例,方便快速上手。
多线程适用于处理大量I/O时使用,多进程适用于密集型CPU计算时使用。由于GIL的限制,python端的多线程实际是假的多线程,也就是真正计算时,其实用的是单线程,只有当有I/O时,I/O才会与计算并行,此时为多线程,当I/O结束时,GIL上锁,又切换为单线程计算,因此,python多线程适用于大量I/O时,比较快。
concurrent.futures模块支持多进程、多线程快速切换,推荐使用!
concurrent.futures模块
import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed
def multiprocessing_worker(num_list):
x1s, x2s = [], []
for i in num_list:
x1s.append(i*i)
x2s.append((i+1)**2)
return x1s, x2s
num = 1000000
t1 = time.time()
#多线程:ThreadPoolExecutor, 多进程:ProcessPoolExecutor. 直接切换即可 #
# excutor = ProcessPoolExecutor(max_workers=32) # 多进程
excutor = ThreadPoolExecutor(max_workers=32) # 多线程
num_list = range(num)
num_processes = 2
delta = num // num_processes
futures = list()
for i in range(0, num, delta):
# multiprocessing_worker支持多个参数输入,直接在后边加即可
fut = excutor.submit(multiprocessing_worker, num_list[i:i+delta])
futures.append(fut)
# 等待进程、线程结束,返回函数运行结果
for fut in as_completed(futures):
# pass
print(fut.result())
t2 = time.time()
multiprocessing模块
使用multiprocess的Pool进行多进程使用,示例如下
############################ 多进程 ####################################
import multiprocessing as mp
def multiprocessing_worker(num_list):
x1s, x2s = [], []
for i in num_list:
x1s.append(i*i)
x2s.append((i+1)**2)
return x1s, x2s
num_list = range(num)
num_processes = 2
delta = num // num_processes
# Multiprocessing.Pool可以提供指定数量的进程供用户调用,当有新的请求提交到pool中时,
# 如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定
# 最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行它。
pool = mp.Pool(processes=16)
results = list()
for i in range(0, num, delta):
# 注意,当只有一个参数输入时,args后必须有",", 不可直接args=(num_list[i: i+delta])
res = pool.apply_async(multiprocessing_worker, args=(num_list[i: i+delta],))
results.append(res)
pool.close()
pool.join()
# 等待进程结束,返回函数运行结果
for res in results:
# pass
print(res.get())
t3 = time.time()
使用multiprocessing.Process,默认Process不支持函数数据返回,但是可以通过Queue实现
import multiprocessing as mp
def job(q, num_list, k):
res = 0
for i in num_list:
res = i**2 + k
# 打印顺序比较乱,因为进程无序
print(res)
q.put(res)
if __name__ == '__main__':
q = mp.Queue()
num = 20
num_list = range(num)
num_processes = 5
delta = num // num_processes
job_list = []
for i in range(0, len(num_list), delta):
p = mp.Process(target=job, args=(q, num_list[i: i+delta], i))
job_list.append(p)
p.start()
# 阻塞进程,等待所有进程执行结束
for p in job_list:
p.join()
# 按顺序打印
for _ in range(q.qsize()):
print(q.get())