Python 如何从multiprocessing.queue中的进程中释放内存?

Python 如何从multiprocessing.queue中的进程中释放内存?,python,memory,python-multiprocessing,Python,Memory,Python Multiprocessing,我有一个程序,试图预测我一周内发送的每一封电子邮件的转化率(通常是7封)。输出是7个不同的文件,其中包含每个客户的预测分数。连续运行这些程序可能需要将近8个小时,因此我尝试使用多处理将它们并行化。这可以很好地加快速度,但我注意到,在一个进程完成后,它似乎会保留其内存,直到没有剩余内存,并且其中一个进程在没有完成任务的情况下被系统杀死 我基于以下代码,因为我需要限制由于内存限制而一次启动的进程数量。我想要的是,当一个进程完成时,它会向系统释放内存,为下一个工作进程释放空间 下面是处理并发性的代码:

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

我基于以下代码,因为我需要限制由于内存限制而一次启动的进程数量。我想要的是,当一个进程完成时,它会向系统释放内存,为下一个工作进程释放空间

下面是处理并发性的代码:

def 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()
以下是实际工作代码(如果有帮助):

def 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()) + '\n'

    # 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()) + '\n'
    with open(output_file,'wb') as f:
        pickle.dump(outdict,f)

我假设,就像您链接的示例一样,您正在使用Queue.Queue()作为队列对象。这是一个阻塞队列,这意味着调用
queue.get()
将返回一个元素,或者等待/阻塞,直到它返回一个元素。 尝试将您的
工作\u控制器
功能更改为以下内容:

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:
          return
      print key

      work_loop(key)
      out_list.append(key)
虽然上述解决了阻塞问题,但它引发了另一个问题。在线程生命期开始时,in_队列中没有任何项目,因此线程将立即结束

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

global 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()

您是否确定内存泄漏是由于多处理造成的?如果连续调用
work\u循环
函数,内存消耗还会增加吗?@ali\m谢谢你的评论。你是对的,有某种内存泄漏。有趣的是(或者不是?),程序不会在每次迭代中占用新的内存块——它只会根据需要占用更多的内存。因此,例如,如果一次
work\u loop
迭代占用1gb内存,下一次占用500mb内存,则程序使用的总内存为1gb。但是如果下一次迭代需要2gb,那么程序将保留整个2gb。我仍在寻找一种方法,将其释放回系统,这对我来说确实是正常的行为。当Python对象超出范围(或者手动删除)时,分配给它的内存将不会释放,直到对象被垃圾回收。发生这种情况的确切时间是相当不可预测的,但是您可以使用
gc.collect()
强制垃圾收集。但是,即使在对象被垃圾收集之后,操作系统也可能不会回收刚刚释放的内存,因此,如果您正在观察Python进程的内存使用情况,您不应该期望它立即下降。如果每次运行
work\u loop()
,Python进程的内存使用量都会增加一些,然后我会怀疑你在
工作循环
中有内存泄漏。无论如何,我认为你不可能得到一个非常满意的答案,因为如果没有剩下的代码和输入数据,就不可能重现问题。如果您可以将代码精简为一个新的代码,那么您将有更好的机会(在这个过程中,您很有可能自己确定原因)。