在大文件Python上执行多处理的最佳方法

在大文件Python上执行多处理的最佳方法,python,multiprocessing,Python,Multiprocessing,我有一个python脚本,它将遍历>1000个元素的列表,在一个大文件中找到变量,然后输出结果。我正在读取整个文件>1000次。我尝试使用多处理,但没有多大帮助。 以下是我正在尝试做的: import gzip from multiprocessing.pool import ThreadPool as Pool def getForwardIP(clientIP, requestID): with gzip.open("xyz.log") as infile: for lin

我有一个python脚本,它将遍历>1000个元素的列表,在一个大文件中找到变量,然后输出结果。我正在读取整个文件>1000次。我尝试使用多处理,但没有多大帮助。 以下是我正在尝试做的:

import gzip
from multiprocessing.pool import ThreadPool as Pool

def getForwardIP(clientIP, requestID):
   with gzip.open("xyz.log") as infile:
     for lines in infile:
        line= lines.split(" ")
        myRequestID= line[0]
        forwardIP= line[1]
        if myRequestID==requestID:
           print forwardIP
if __name__== "__main__":
    pool_size=8
    pool= Pool(pool_size)
    request_id_list= list()
    #request_id_list contains >1000 elements
    for id in request_id_list:
      pool.apply_async(getForwardIP, ("1.2.3.4.", id, ))
   pool.close()
   pool.join()
有没有更快的办法?任何帮助都将不胜感激。谢谢

编辑

我在这里写我的全部代码 谢谢大家的建议。现在我将文件写入列表,而不是读取1000次。我试图对for循环进行多处理,但没有成功。代码如下:

import gzip
import datetime
from multiprocessing.pool import ThreadPool as Pool

def getRequestID(r_line_filename):
  requestIDList= list()
  with gzip.open(r_line_filename) as infile:
  #r_line_filename is a file with request_id and client_ip
    for lines in infile:
        line= lines.split(" ")
        requestID= line[1].strip("\n")
        myclientIP= line[0]
        if myclientIP==clientIP:
            requestIDList.append(requestID)  
   print "R line List Ready!"
   return(requestIDList)  



def getFLineList(fFilename):
   fLineList= list()
   with gzip.open(fFilename) as infile:
   #fFilename is a file with format request_id, forward_ip, epoch time
     for lines in infile:
        fLineList.append(lines.split())
  print "F line list ready!"
  return(fLineList)

def forwardIP(lines, requestID):
 myrequestID= lines[0]
 forwardIP= lines[1]
 epoch= int(lines[2].split(".")[0])
 timex= datetime.datetime.fromtimestamp(epoch).strftime('%Y-%m-%d %H:%M:%S')
 if myrequestID==requestID:
    print "%s %s %s"%(clientIP, timex, forwardIP)

if __name__== "__main__":
 pool= Pool()
 clientIP= "x.y.z.a"
 rLineList= getRequestID("rLine_subset.log.gz")
 fLineList= getFLineList("fLine_subset.log.gz")
 for RID in rLineList:
    for lines in fLineList:
        pool.apply_async(forwardIP, (lines, RID,))
    pool.close()
    pool.join()

多处理部件不工作。实际上,这个要慢得多。如果我不进行多重处理,只遍历列表,速度会更快。提前谢谢你的帮助

确实有一种更快的方法。不要在1000次内读取和解析该文件。相反,读入它一次,解析它一次,然后存储它。文件I/O是任何语言中最慢的操作之一。内存处理速度更快

类似这样的东西显然未经测试,因为我无法访问xyz.log。对于老鹰:显然我也没有分析它,但我有一个鬼鬼祟祟的怀疑,读一次文件比读1000次要快:

import gzip

def readFile():
  my_lines = []
  with gzip.open("xyz.log") as infile:
     for lines in infile:
        line = lines.split(" ")
        my_lines.append(line)

  return my_lines

def getForwardIp(lines, requestID): #Doesn't look like you need client IP (yet), so I nuked it
  myRequestID= line[0]
  forwardIP= line[1]
  if myRequestID==requestID:
     print forwardIP

if __name__ == "__main__":
  parsed_lines = readFile()
  request_id_list= list()
  #request_id_list contains >1000 elements
  for id in request_id_list:
    getForwardIp(parsed_lines, requestID)

确实有一种更快的方法。不要在1000次内读取和解析该文件。相反,读入它一次,解析它一次,然后存储它。文件I/O是任何语言中最慢的操作之一。内存处理速度更快

类似这样的东西显然未经测试,因为我无法访问xyz.log。对于老鹰:显然我也没有分析它,但我有一个鬼鬼祟祟的怀疑,读一次文件比读1000次要快:

import gzip

def readFile():
  my_lines = []
  with gzip.open("xyz.log") as infile:
     for lines in infile:
        line = lines.split(" ")
        my_lines.append(line)

  return my_lines

def getForwardIp(lines, requestID): #Doesn't look like you need client IP (yet), so I nuked it
  myRequestID= line[0]
  forwardIP= line[1]
  if myRequestID==requestID:
     print forwardIP

if __name__ == "__main__":
  parsed_lines = readFile()
  request_id_list= list()
  #request_id_list contains >1000 elements
  for id in request_id_list:
    getForwardIp(parsed_lines, requestID)

我可能会在单个大文件中扫描所有请求的ID,然后充分利用线程池调用getForwardIP


您可以将单个大文件划分为多个区域,并让多个工作进程处理文件的不同分区,但这种方法存在一些挑战,可能无法在所有文件系统上运行。

我可能会在单个大文件中扫描所有请求的ID,然后充分利用线程池调用getForwardIP


您可以将单个大文件划分为多个区域,并让多个工作人员处理文件的不同分区,但这种方法存在一些挑战,可能无法在所有文件系统上运行。

我同意mwm314的观点,即您不应该读取文件1000次

我假设您没有给我们完整的代码,因为client_ip参数似乎没有使用,但是在这里我重写了它,只打开文件一次,并且只对文件中的每一行迭代一次。我还修改了getForwardIP以获取请求ID列表,并立即将其转换为一个集合,以获得最佳的查找性能

import gzip


def getForwardIP(client_ip, request_ids):
    request_ids = set(request_ids)  # to get O(1) lookup
    with gzip.open("xyz.log") as infile:
        for lines in infile:
            line = lines.split(" ")
            found_request_id = line[0]
            found_forward_ip = line[1]
            if found_request_id in request_ids:
                print found_forward_ip


if __name__ == "__main__":
    request_id_list = list()
    # request_id_list contains >1000 elements
    getForwardIP("1.2.3.4.", request_id_list)

我同意mwm314的说法,即您不应该将文件读取1000次

我假设您没有给我们完整的代码,因为client_ip参数似乎没有使用,但是在这里我重写了它,只打开文件一次,并且只对文件中的每一行迭代一次。我还修改了getForwardIP以获取请求ID列表,并立即将其转换为一个集合,以获得最佳的查找性能

import gzip


def getForwardIP(client_ip, request_ids):
    request_ids = set(request_ids)  # to get O(1) lookup
    with gzip.open("xyz.log") as infile:
        for lines in infile:
            line = lines.split(" ")
            found_request_id = line[0]
            found_forward_ip = line[1]
            if found_request_id in request_ids:
                print found_forward_ip


if __name__ == "__main__":
    request_id_list = list()
    # request_id_list contains >1000 elements
    getForwardIP("1.2.3.4.", request_id_list)

为什么不在脚本开始时读取文件,并使用字典或列表。每次调用getForwardIP时,都会从头开始读取文件。我不认为这样做有什么意义,如果文件太大,无法在内存中容纳request_id->ip map,您可以使用这里描述的技术,在收集的一组偏移量上运行每个进程,为什么不在脚本开始时读取文件,并使用字典或列表。每次调用getForwardIP时,都会从头开始读取文件。我不认为这样做有什么意义,如果文件太大,并且无法在内存中容纳request\u id->ip映射,您可以使用这里描述的技术,在收集的一组偏移上运行每个进程。谢谢!由于文件太大,我们是否有可能无法将整个内容存储在内存/列表中?如果是这样的话,您将经历一段艰难的时光。你有两个选择。您可以使用AWS/Spark之类的工具为一次性工作获取更多内存,也可以购买更大的机器。或者,如果请求\u id\u列表的顺序与它们在使用yield关键字的文件中的显示顺序相同,则可以使用生成器而不是返回列表。这是实际情况吗?它不适合记忆吗?如果不重要的话,不要太多地使用理论;它确实适合内存,但在这种情况下。我担心的是,如果我必须处理更大的文件,我肯定必须这样做,那么还有什么其他选择呢。对于这一个,您的解决方案起了作用。谢谢谢谢由于文件太大,我们是否有可能无法将整个内容存储在内存/列表中?如果是这样,您将
过得不愉快。你有两个选择。您可以使用AWS/Spark之类的工具为一次性工作获取更多内存,也可以购买更大的机器。或者,如果请求\u id\u列表的顺序与它们在使用yield关键字的文件中的显示顺序相同,则可以使用生成器而不是返回列表。这是实际情况吗?它不适合记忆吗?如果不重要的话,不要太多地使用理论;它确实适合内存,但在这种情况下。我担心的是,如果我必须处理更大的文件,我肯定必须这样做,那么还有什么其他选择呢。对于这一个,您的解决方案起了作用。谢谢对这不是全部代码。将列表设置为帮助。在不同进程中调用列表的每个元素会进一步优化它吗?您的意思是在线程池中的request\u id中找到request\u id时运行?你可以试试!由于集合上的非写操作是线程安全的,我认为它不会造成任何伤害。是的!请参考编辑手册。我已经发布了全部代码。在你的新代码中,我有一种预感,瓶颈现在是stdout。如果您在Unix系统上,请尝试使用python yourscript.py>output_file.txt在shell/Terminal中运行脚本。我正在使用相同的方法运行脚本。是的!这不是全部代码。将列表设置为帮助。在不同进程中调用列表的每个元素会进一步优化它吗?您的意思是在线程池中的request\u id中找到request\u id时运行?你可以试试!由于集合上的非写操作是线程安全的,我认为它不会造成任何伤害。是的!请参考编辑手册。我已经发布了全部代码。在你的新代码中,我有一种预感,瓶颈现在是stdout。如果您在Unix系统上,请尝试使用python yourscript.py>output_file.txt在shell/Terminal中运行脚本。我正在使用相同的方法运行脚本。这就是我现在要做的。在不同的进程中调用gerForwardIP。谢谢这就是我现在要做的。在不同的进程中调用gerForwardIP。谢谢