排队工作,不使用大量内存

时间:2011-12-28 14:40:00

标签: python

我正在尝试设置一个线程正在编写工作列表并且另一个线程正在读取列表并从中工作的东西。这个列表可能非常大,所以要阻止这个列表保存在内存中我想把它写在一个文件中(或者保留内存生成器吗?)。

我把一个小的可运行的例子放在作者的睡眠中,以便读者能够赶上。我想知道当读者“超越”作家时,我怎能让读者不要停下来。我看着使用.seek.tell,但我的行为很怪异,我不确定这是正确的路线。

另一个问题是,这是一个明智的想法吗?也许有一种更优雅的方式我可以在不使用大量内存的情况下排队字符串列表。

import threading,time

class Writer(threading.Thread):

  lock= threading.Lock()

  def __init__(self,file_path,size):
    threading.Thread.__init__(self)
    self.file_path= file_path
    self.size= size
    self.i=0

  def how_many(self):
    with self.lock:
      print "Reader starting, writer is on",self.i

  def run(self):
    f=open(self.file_path,"w")
    for i in xrange(self.size):
      with self.lock:
        self.i=i
      if i%1000==0:
        time.sleep(0.1)
      f.write("%s\n"%i)
    f.close()

class Reader(threading.Thread):

  def __init__(self,file_path):
    threading.Thread.__init__(self)
    self.file_path= file_path

  def run(self):
    f=open(self.file_path,"r")
    line=0
    for line in f:
      pass
    print "Reader got to: %s"%line.strip()


if __name__ == "__main__":
  a= Writer("testfile",2000000)
  b= Reader("testfile")
  a.start()
  time.sleep(1)
  a.how_many()
  b.start()

3 个答案:

答案 0 :(得分:2)

我确实解决了这个问题,使用了缓冲文件队列,队列在内存和文件之间展开。将项目放入队列但如果队列中的项目超过指定的队列大小,则任何溢出都将存储在文件中以保留内存,并且get将排除队列

如果有人想要做类似的事情我把它放在github上here

答案 1 :(得分:0)

为了在线程之间发送消息,Queue类非常方便。使用from Queue import Queue导入它,构造一个,并将队列对象传递给每个线程。它支持多个生产者和使用者,您可以将大多数Python对象放入队列中 - 列表,对象,迭代器等。

要使用此队列传输大量数据,只需一次将一个对象写入队列,并在使用者中使用生成数据的生成器函数。如果生产者比消费者更快,队列支持深度限制。

答案 2 :(得分:0)

多处理JoinableQueue类旨在允许限制在等待子线程/进程使用任务时可能构建的积压。我假设你正在从一个文件中读取工作,并且该文件太大而无法一次性容纳在内存中。

以下是我尝试一种应该限制内存使用的解决方案。在这个例子中,我处理换行的一系列日期,将它们转换成标准格式,然后将它们写回新文件。

我绝不是多处理模块的专家,所以如果有人看到错误/更好的方法,我希望听到它。

from multiprocessing import Process, Queue, JoinableQueue
import time

date_formats =  [
    "%Y%m",
    "%Y-%m-%d", 
    "%y-%m-%d", 
    "%y%m%d", 
    "%Y%m%d", 
    "%m/%d/%Y", 
    "%m/%d/%y", 
    "%m/%d/%Y %H:%M",
    "%m%d%y", 
    "%m%d%Y", 
    "%B, %d %Y", 
    "%B, %d %y", 
    "%d %B, %Y", 
    "%d %B, %y",
    "%B %d %Y", 
    "%B %d %y", 
    "%B %d, %Y", 
    "%B %d, %y", 
    "%B %d %Y", 
    "%B %d %y",
    "%b %d %Y", 
    "%b %d, %Y", 
    "%b %d %y", 
    "%b %d, %y", 
    "%d-%b-%y", 
    "%Y-%m-%d %H:%M:%S"
]

def convert_date(date):
    date = date.strip()
    for dateformat in date_formats:
        try:
            converted = time.strptime(date, dateformat)
            converted = time.strftime("%Y-%m-%d", converted)
            return converted
        except ValueError:
            continue

def writer(result_queue):
    f = open("iso_dates.out", "wb")
    while True:
        try:
            date = result_queue.get(timeout=1)
            f.write(date + '\n')
        except:
            break       
    f.close()

def worker(work_queue, result_queue):
    while True:
        date = work_queue.get()

        if not date:
            break

        result_queue.put(convert_date(date))
        work_queue.task_done()

dates        = open("dates.out", "rb")
work_queue   = JoinableQueue(512) #allow no more than 512 items on queue
result_queue = Queue()
writer_proc  = Process(target=writer, args=(result_queue,))
worker_procs = 2

for i in range(worker_procs):
    p = Process(target=worker, args=(work_queue, result_queue))
    p.daemon = True
    p.start()

writer_proc.start()
for date in dates:
    work_queue.put(date) #will block until tasks are consumed if maxsize is encountered

work_queue.join()
dates.close()