在多处理中按模块划分行

时间:2018-07-19 06:22:07

标签: python process queue multiprocessing

我想将大文件放入小文件中。文件中大约有200万个ID,我想按模块对它们进行排序。运行程序时,应询问要分割主文件的文件数。(x = int(input))。我想按模块功能分隔文件。我的意思是,如果ID%x == 1,则应将此ID分别添加到q1和f1。但是它只添加了满足需求的第一行。

import multiprocessing
    def createlist(x,i,queue_name):
        with open("events.txt") as f:
            next(f)
            for line in f:
                if int(line) % x == i:
                    queue_name.put(line)
    def createfile(x,i,queue_name):
        for i in range(x):
            file_name = "file{}.txt".format(i+1)
            with open(file_name, "w") as text:
                text.write(queue_name.get())
    if __name__=='__main__':
        x= int(input("number of parts "))
        i = 0
        for i in range(x):
            queue_name = "q{}".format(i+1)
            queue_name = multiprocessing.Queue()
            p0=multiprocessing.Process(target = createlist, args = (x,i,queue_name,))
            process_name = "p{}".format(i+1)
            process_name = multiprocessing.Process(target = createfile, args = (x,i,queue_name,))
            p0.start()
            process_name.start()

1 个答案:

答案 0 :(得分:0)

您的createfile有两个功能问题。

  1. 它仅从队列中读取一次,然后终止
  2. 它第二次迭代所需子集数量的范围,因此,即使在解决了单个队列读取问题之后,您仍然得到一个写入文件和parts - 1个空文件。

要解决您的问题,请使createfile像这样:

def createfile(i, queue_name): # Note: x has been removed from the args
    file_name = "file{}.txt".format(i + 1)
    with open(file_name, "w") as text:
        while True:
            if queue.empty():
                break
            text.write(queue.get())

由于x已从createfile的参数中删除,因此您也将从流程实例中删除它:

process_name = multiprocessing.Process(target = createfile, args = (i,queue_name,))

但是...不要这样。所需的子集越多,创建的进程和队列就越多(每个子集两个进程和一个队列)。这是您创建的很多的开销。

虽然每个输出文件都有一个负责任的进程来写可能仍然有意义,但让多个进程完全读取同一个(巨大)文件却没有意义。

我对包含1000行的输入文件做了一些计时和测试,每个文件由0到9999之间的一个随机整数组成。我创建了三种算法,并在跟踪执行时间的同时进行了十次迭代。我对所需数量的1、2、3、4、5和10的子集进行了此操作。对于下图,我采用了每个系列的平均值。

execution time

orwqpp(绿色):是每部分一个读写器队列。 您的方法。每增加一个子集,执行时间平均增加0.48秒。

orpp(蓝色):每部分一个读者。这是一个通用的编写器过程,该过程负责写入所有文件。每增加一个子集,执行时间平均增加0.25秒。

of(黄色):是一对一的。一项功能,无需在单独的过程中运行,只需一次即可读写。每增加一个子集,执行时间平均增加0.0014秒。

请记住,这些数字是使用输入文件的1/2000大小创建的。类似于您的方法的过程是如此迅速地完成,彼此之间几乎是相互阻碍的。一旦输入大到足以使进程运行更长的时间,CPU资源的争用就会增加,随着请求更多的子集,拥有更多进程的代价也会增加。

这是一对一的方法:

def one_for_all(parts):
    handles = dict({el: open("file{}.txt".format(el), "w") for el in range(parts)})
    with open("events.txt") as f:
        next(f)
        for line in f:
            fnum = int(line) % parts
            handles.get(fnum).write(line)
    [h.close() for h in handles.values()]


if __name__ == '__main__':
    x = int(input("number of parts "))
    one_for_all(x)

当前,这基于模运算的结果来命名文件,因此int(line) % parts为0的数字将位于file0.txt中,依此类推。 如果不希望这样,只需在格式化文件名时加1:

handles = dict({el: open("file{}.txt".format(el+1), "w") for el in range(parts)})