Python multiprocessing

数据处理,遇到几千万上亿级别的,一次几十个小时,利用并行可以有效减少时长。

网上讲原理的很多。

主要放一下自己跑通的一个小demo,备忘。

 

 

Pool是最简单的。

pool.apply()可以并行一些不需要返回值的函数。

poo.apply_async() 可以获得返回值。

 

处理pandas数据,基本都是需要返回值的,上一个apply_async的例子。

原本需要十几个小时,4路并行后降低至4小时。

import multiprocessing

def get_userset_dict(idd,batch_items,train_csv):
    userset_dict = {}
    for item in tqdm(batch_items):
        userset_dict[item] =set(train_csv[train_csv['item_id']==item]['buyer_admin_id'])
    print(idd,'subprocess complete')
    return userset_dict


pool = multiprocessing.Pool(processes=4)
result = []
for i in range(4):
    batch_items= all_items[i*720000:(i+1)*720000]
    result.append(pool.apply_async(get_userset_dict, (i,batch_items,train_csv)))

print("The number of CPU is:" + str(multiprocessing.cpu_count()))
for p in multiprocessing.active_children():
    print("child p.name: " + p.name + "\t p.id: " + str(p.pid))


pool.close()
pool.join()
print('all right!')



#-----------打印结果------------
The number of CPU is:12
child p.name: ForkPoolWorker-12	 p.id: 5216
child p.name: ForkPoolWorker-11	 p.id: 5215
child p.name: ForkPoolWorker-10	 p.id: 5214
child p.name: ForkPoolWorker-9	 p.id: 5213

100%|██████████| 652048/652048 [3:42:48<00:00, 48.78it/s]  
3 subprocess complete

100%|██████████| 720000/720000 [3:59:55<00:00, 50.02it/s]
2 subprocess complete

100%|██████████| 720000/720000 [4:00:08<00:00, 49.97it/s]
1 subprocess complete

100%|██████████| 720000/720000 [4:00:19<00:00, 49.93it/s]
0 subprocess complete

all right!

现在理论上,result这个list里面有我们的返回值,如何获取呢?

#apply_async返回的是"返回值的对象"
#需要使用.get()方法进一步获得返回值
for d in result:
    print(d,',',type(d.get()))


#<multiprocessing.pool.ApplyResult object at 0x7f2794a64518> , <class 'dict'> 
#<multiprocessing.pool.ApplyResult object at 0x7f2794a0b780> , <class 'dict'> 
#<multiprocessing.pool.ApplyResult object at 0x7f2794a0bb00> , <class 'dict'>
#<multiprocessing.pool.ApplyResult object at 0x7f28582eda20> , <class 'dict'> 


#结果合并
userset_dict ={}
for d in result:
    userset_dict.update(d.get())

pickle.dump(userset_dict,open('./data/userset_dict.pkl','wb'))
print('saved')

 

注意,我没研究过.get()的次序问题。

因为这个需求只用返回dict,对数据之间的次序关系无所谓。

不同sub-process的结束时间不同,有可能append的次序也不同。

对次序有要求的任务,要小心。

 

 

 

下面这种理论上功能更高级,还可以开管道,但我不知道怎么拿到返回值。

import multiprocessing

train_csv = pickle.load(open('./data/train_csv.pkl','rb'))
all_items = sorted(list(set(train_csv['item_id'])))

def get_userset_dict(idd,batch_items,train_csv):
    userset_dict = {}
    for item in tqdm(batch_items):
        userset_dict[item] =set(train_csv[train_csv['item_id']==item]['buyer_admin_id'])
    print(idd,'subprocess complete')
    return userset_dict


p_list = []
for i in range(4):
    batch_items= all_items[i*720000:(i+1)*720000]
    p_list.append(multiprocessing.Process(target=get_userset_dict, args=(i,batch_items,train_csv)))

ts = time.time()

for p in p_list:
    p.start()

print("The number of CPU is:" + str(multiprocessing.cpu_count()))

for p in multiprocessing.active_children():
    print("child p.name: " + p.name + "\t p.id: " + str(p.pid))

for p in p_list:
    p.join()
    

print(time.time()-ts)

 

 

补坑说明

python的multiprocess.pool不共享内存,传入的值如果改变就相当于复制了好几分。(从我监控内存变化来看是这样的)

需要确保任务运行过程中的临时变量小于总内存,不然一损具损,全部宕机。

而且,在pool.apply_async调用的函数内,使用pickle.dump有概率出现莫名其妙的key error等错误,没找到原因。(不使用pool直接跑目标函数不会报错) 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值