为什么进程不会在多进程中终止

时间:2016-04-07 07:00:46

标签: python list multiprocessing

昨天我在python中使用多处理处理了一个大约有2000万行的日志文件。

  1. 启动一个名为“producer”的进程,逐行读取文件并将其放入队列中。
  2. 启动名为'consumer i'的三个进程从队列中获取一行并分析它以获取ip。
  3. 在main函数中,我启动这些进程并等待join()。
  4. 代码低于

    ~280dp

    结果很奇怪消费者流程在完成工作后不会终止,并且主要功能在join()时被阻止。

    使用不同的测试和重新编码进行测试:

    • 使用 test_get_ip()而无需多处理来处理小型或大型日志文件,效果很好。
    • 使用 main()进行多处理来处理大型日志文件,它将在join()处阻塞。每个get_ip进程都会打印“stop get_ip XXXX”,但不会终止。
    • 使用 main()处理较小的日志文件,包含2,000行,效果也很好。 get_ip将终止。
    • 如果我不在get_ip()中的列表ips中存储ip,它可以正常运行,包含小型或大型日志文件。

    那么,问题是什么?列表中是否有限制?我有什么遗漏的吗?

    我的机器环境是:

    from multiprocessing import Process, Queue
    from Queue import Empty
    import os
    import time    
    
    
    def put_ip(src, q, number):
        """ 
        read file line by line, and put it to queue
        """
        print "start put_ip: %d" % os.getpid()
        with open(src) as f:
            for line in f:
                q.put(line)
            for i in range(number):
                q.put(EOFError)
        print "stop put_ip"
    
    
    def get_ip(lock, src, result, index):
        """ 
        fetch line, and extract ip from it
        """
        print "start get_ip %d: %d" % (index, os.getpid())
        ips = []
        while True:
            line = src.get()
            if line == EOFError:
                print "%d get EOFError" % index
                break
            else:
                res = json.loads(line.strip())
                # process res, get ip
                ips.append(ip)
        print "get_ip %d get %d ips" % (os.getpid(), len(ips))
        result.put('\n'.join(ips))
        ips = []
        print "stop get_ip %d" % os.getpid()
        return
    
    
    def test_get_ip(src, dest, number):
        """ 
        test with single process
        """
        srcq = Queue()
        result = Queue()
    
        with open(src) as f:
            for line in f:
                # if 'error' not in line:
                srcq.put(line)
            for i in range(number):
                srcq.put(EOFError)
    
        get_ip(srcq, result, 0)
    
    
    def main(src, dest, number):
        """ 
        with multiprocess
        """
        srcq = Queue()
        result = Queue()
    
        producer = Process(target=put_ip, args=(src, srcq, number))
    
        consumers = [Process(target=get_ip, args=(srcq, result, i)) for i in xrange(number)]
    
        print 'start at %s' % time.asctime()
        starttime = time.time()
    
        producer.start()
        for consumer in consumers:
            consumer.start()
    
        producer.join()
        for consumer in consumers:
            consumer.join()
    
        with open(dest, 'w') as w:
            while True:
                try:
                    res = result.get_nowait()
                    w.write(res +'\n')
                except Empty:
                    print 'Empty'
                    break
    
        print "time: %f" % (time.time()-starttime)
    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument('-i', dest='src', required=True)
        parser.add_argument('-o', dest='dest', required=True)
        parser.add_argument('-n', dest='number', type=int, default=2)
    
        args = parser.parse_args()
    
        main(args.src, args.dest, args.number)
        # test_get_ip(args.src, args.dest, args.number)
    

    谢谢你的时间!

1 个答案:

答案 0 :(得分:0)

我认为您的问题是您正在缓冲所有数据并仅在消费者完成后发送结果。

假设运行get_ip()的进程已在列表中收集了1M个ip地址。现在,在终止之前,它需要序列化所有这些数据并将其传递到Queue,然后main()函数将接收并反序列化所有那个数据。

我的建议是你将IP地址直接放入结果队列中,然后让main()进程获取它们并在它们到来时写入它们。