python processpoolexector 释放内存_关于python:如何在multiprocessing.queue中从Process中释放内存?...

我有一个程序试图预测一周内发送的每封电子邮件的电子邮件转换(因此,通常是7封)。 输出是7个不同的文件,每个客户的预测得分。 串行运行这些可能需要8个小时,因此我尝试使用multiprocessing将它们并行化。 这样可以很好地加快处理速度,但是我注意到,在进程完成后,它似乎会保留在其内存中,直到没有剩余,并且其中一个进程被系统杀死而没有完成其任务。

我在此答案中基于"手动池"示例创建了以下代码,因为由于内存限制,我需要限制立即启动的进程数。 我想要的是,当一个进程完成时,它将内存释放到系统中,从而为下一个工作人员释放了空间。

下面是处理并发的代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31def work_controller(in_queue, out_list):

while True:

key = in_queue.get()

print key

if key == None:

return

work_loop(key)

out_list.append(key)

if __name__ == '__main__':

num_workers = 4

manager = Manager()

results = manager.list()

work = manager.Queue(num_workers)

processes = []

for i in xrange(num_workers):

p = Process(target=work_controller, args=(work,results))

processes.append(p)

p.start()

iters = itertools.chain([key for key in training_dict.keys()])

for item in iters:

work.put(item)

for p in processes:

print"Joining Worker"

p.join()

这是实际的工作代码,如果有帮助的话:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31def work_loop(key):

with open('email_training_dict.pkl','rb') as f:

training_dict = pickle.load(f)

df_test = pd.DataFrame.from_csv(test_file)

outdict = {}

target = 'is_convert'

df_train = train_dataframe(key)

features = data_cleanse(df_train,df_test)

# MAIN PREDICTION

print 'Start time: {}'.format(datetime.datetime.now()) + '

'

# train/test by mailer

X_train = df_train[features]

X_test = df_test[features]

y_train = df_train[target]

# run model fit

clf = imbalance.ImbalanceClassifier()

clf = clf.fit(X_train, y_train)

y_hat = clf.predict(X_test)

outdict[key] = clf.y_vote

print outdict[key]

print 'Time Complete: {}'.format(datetime.datetime.now()) + '

'

with open(output_file,'wb') as f:

pickle.dump(outdict,f)

您如何确定内存泄漏是由于多处理造成的?如果串行调用work_loop函数,是否还会看到内存消耗增加的情况?

@ali_m感谢您的评论。您是正确的,存在某种内存泄漏。有趣的是(或不?),该程序不会为每次迭代占用一个新的内存块-它只需要按需占用更多内存。因此,例如,如果work_loop的一个迭代占用1gb的内存,而下一迭代占用500mb,则该程序使用的总内存为1gb。但是,如果下一次迭代花费2gb,则程序将保留整个2gb。我仍在寻找将其释放回系统的方法

对我而言,这实际上听起来像是正常行为。当Python对象超出范围(或如果您手动删除)时,分配给它的内存将不会被释放,直到该对象被垃圾回收为止。确切的说,这种情况何时发生是很难预测的,但是您可以使用gc.collect()强制进行垃圾回收。但是,即使在对象被垃圾回收后,操作系统也可能不会回收刚刚释放的内存,因此,如果您看着Python进程的内存使用情况,则不应期望它立即崩溃。

如果每次运行work_loop()时Python进程的内存使用量都有一定的增加,那么我怀疑您在work_loop中存在内存泄漏。

无论如何,我认为您不可能就目前的问题获得非常令人满意的答案,因为如果没有其余的代码和输入数据就无法重现问题。如果您可以将代码精简为MCVE,则您将有更好的机会(这是一个很好的机会,您可以在此过程中自行确定原因)。

我假设,就像您链接的示例一样,您正在使用Queue.Queue()作为队列对象。 这是一个阻塞队列,这意味着对queue.get()的调用将返回一个元素,或者等待/阻塞直到它可以返回一个元素。

尝试将work_controller函数更改为以下内容:

1

2

3

4

5

6

7

8

9

10def work_controller(in_queue, out_list):

while True: # when the queue is empty return

try:

key = in_queue.get(False) # add False to not have the queue block

except Queue.Empty:

return

print key

work_loop(key)

out_list.append(key)

尽管以上解决了阻塞问题,但又引发了另一个问题。 在线程寿命开始时,in_queue中没有任何项,因此线程将立即结束。

为了解决这个问题,我建议您添加一个标志以指示是否可以终止。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37global ok_to_end # put this flag in a global space

def work_controller(in_queue, out_list):

while True: # when the queue is empty return

try:

key = in_queue.get(False) # add False to not have the queue block

except Queue.Empty:

if ok_to_end: # consult the flag before ending.

return

print key

work_loop(key)

out_list.append(key)

if __name__ == '__main__':

num_workers = 4

manager = Manager()

results = manager.list()

work = manager.Queue(num_workers)

processes = []

ok_to_end = False # termination flag

for i in xrange(num_workers):

p = Process(target=work_controller, args=(work,results))

processes.append(p)

p.start()

iters = itertools.chain([key for key in training_dict.keys()])

for item in iters:

work.put(item)

ok_to_end = True # termination flag set to True after queue is filled

for p in processes:

print"Joining Worker"

p.join()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值