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

Python 为什么进程不在多进程中终止,python,list,multiprocessing,Python,List,Multiprocessing,昨天,我使用python中的多处理处理处理了一个大约有2000万行的日志文件 启动名为“producer”的进程,逐行读取文件并将其放入队列 启动三个名为“consumer i”的进程,从队列中提取一行,并对其进行分析以获取ip 在main函数中,我启动这些进程并使用join()等待 代码如下 from multiprocessing import Process, Queue from Queue import Empty import os import time def put

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

  • 启动名为“producer”的进程,逐行读取文件并将其放入队列
  • 启动三个名为“consumer i”的进程,从队列中提取一行,并对其进行分析以获取ip
  • 在main函数中,我启动这些进程并使用join()等待
  • 代码如下

    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)
    
    奇怪的是,使用者进程在完成工作后不会终止,并且主函数在join()处被阻止。

    使用以下不同的套装和代码进行测试:

    • 使用无需多处理的test\u get\u ip()来处理小型或大型日志文件,效果良好
    • 使用带有多处理功能的main()来处理大型日志文件,它将在join()处阻塞。每个get_ip进程将打印“stop get_ip XXXX”,但不会终止
    • 使用main()处理2000行的较小日志文件,效果也很好。get_ip将终止
    • 如果我不将ip存储在get_ip()中的列表ip中,则无论日志文件大小,它都可以正常工作
    那么,有什么问题?列表中有限制吗?有什么我错过的吗

    我的机器环境是:

    Linux 3.19.0-32-generic #37~14.04.1-Ubuntu SMP Thu Oct 22 09:41:40 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux 
    Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
    [GCC 4.8.2] on linux2
    

    谢谢你抽出时间

    我认为您的问题在于,您正在缓冲所有数据,并且只有在消费者完成后才发送结果

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


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

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

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


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

    如您所见,在get_IP()的末尾,我添加了一个调试打印,打印“stop get_IP%d”%os.getpid()。它将在输出端显示。我想结果已经完成了。对吗?但是为什么get_ip进程不终止?可能是在从队列中读取结果之前,它们不会终止。但是为什么使用较小的日志文件,它会终止?在所有使用者进程终止后读取结果。如您所见,在get_ip()的末尾,我添加了一个调试打印,打印“stop get_ip%d”%os.getpid()。它将在输出端显示。我想结果已经完成了。对吗?但是为什么get_ip进程不终止?可能是在从队列中读取结果之前,它们不会终止。但是为什么使用较小的日志文件,它会终止?在所有使用者进程终止后读取结果。