Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用python,我应该在数组中缓存大数据并一次性写入文件吗?_Python_Io_Gevent - Fatal编程技术网

使用python,我应该在数组中缓存大数据并一次性写入文件吗?

使用python,我应该在数组中缓存大数据并一次性写入文件吗?,python,io,gevent,Python,Io,Gevent,我一直有一个gevent驱动的爬虫下载页面。爬虫程序采用生产者-消费者模式,我向队列提供如下数据{method:get,url:xxxx,other_info:yyyy} 现在我想把一些响应汇编成文件。问题是,我不能在每个请求结束时都打开并写入,这会造成io开销,而且数据顺序不正确 我假设我应该对所有请求进行编号,按顺序缓存响应,打开greenlet以循环和组装文件,伪代码可能如下所示: max_chunk=1000 data=[] def wait_and_assemble_file(): #

我一直有一个gevent驱动的爬虫下载页面。爬虫程序采用生产者-消费者模式,我向队列提供如下数据{method:get,url:xxxx,other_info:yyyy}

现在我想把一些响应汇编成文件。问题是,我不能在每个请求结束时都打开并写入,这会造成io开销,而且数据顺序不正确

我假设我应该对所有请求进行编号,按顺序缓存响应,打开greenlet以循环和组装文件,伪代码可能如下所示:

max_chunk=1000
data=[]
def wait_and_assemble_file(): # a loop
    while True:
        if len(data)==28:
            f= open('test.txt','a')
            for d in data:
                f.write(d)
            f.close()
        gevent.sleep(0)

def after_request(response, index): # Execute after every request ends
    data[index]=response  # every response is about 5-25k
有更好的解决办法吗?有数千个并发请求,我怀疑内存使用可能增长太快,或者一次循环太多,或者是意外的

更新:

上面的代码只是演示了数据缓存和文件写入的功能。在实际情况中,可能会有100次循环运行来等待缓存完成并写入不同的文件

更新2

@忍者建议使用队列系统,因此我使用Redis编写了一个替代方案:

def after_request(response, session_id, total_block_count ,index): # Execute after every request ends
    redis.lpush(session_id, msgpack.packb({'index':index, 'content':response}))  # save data to redid

    redis.incr(session_id+':count')
    if redis.get(session_id+':count') == total_block_count: # which means all data blocks are prepared
        save(session_name)


def save(session_name):
  data_array=[]
  texts = redis.lrange(session_name,0,-1)
  redis.delete(session_name)
  redis.delete(session_name+':count')
  for t in texts:
    _d = msgpack.unpackb(t)
    index = _d['index']
    content = _d['content']
    data_array[index]=content

  r= open(session_name+'.txt','w')
  [r.write(i) for i in data_array]
  r.close()

看起来好一点,但我怀疑在Redis中保存大数据是否是个好主意,希望得到更多建议

这取决于数据的大小。如果它很大,它可以减慢内存中所有结构的程序


如果内存不是问题,那么应该将结构保留在内存中,而不是一直从文件中读取。使用concurrents请求反复打开文件不是一个好的解决方案。

这取决于数据的大小。如果它很大,它可以减慢内存中所有结构的程序


如果内存不是问题,那么应该将结构保留在内存中,而不是一直从文件中读取。使用concurrents请求一次又一次地打开文件不是一个好的解决方案。

使用队列系统可能更好地处理类似的问题,而不是每个线程都有自己的文件处理程序。这是因为在编写此文件时,由于每个线程都有自己的处理程序,您可能会遇到竞争条件


就资源而言,除了磁盘写入之外,这不应该消耗太多的资源,假设传递到文件的信息不是非常大(Python在这方面做得非常好)。但是,如果这确实会造成问题,则将文件分块读入内存(并按比例分块写入)可以大大减少此问题,只要这是文件上载的一个选项。

使用队列系统可以更好地处理类似的问题,而不是每个线程都有自己的文件处理程序。这是因为在编写此文件时,由于每个线程都有自己的处理程序,您可能会遇到竞争条件


就资源而言,除了磁盘写入之外,这不应该消耗太多的资源,假设传递到文件的信息不是非常大(Python在这方面做得非常好)。如果这确实会造成问题,那么将文件分块读入内存(并按比例分块写入)可以大大减少此问题,只要这是文件上载的一个选项。

将文件打开一次并保持打开状态如何?(但我不知道万一程序崩溃会发生什么情况)。我不确定写之前的缓存是否有用,因为你的操作系统可能已经在自己做一些缓存了。我的操作系统是ubuntu和maces。除了缓存,我还需要对数据重新排序,因为它们是异步获取的,没有顺序@Basswinckelsw打开文件一次并保持打开状态如何?(但我不知道万一程序崩溃会发生什么情况)。我不确定写之前的缓存是否有用,因为你的操作系统可能已经在自己做一些缓存了。我的操作系统是ubuntu和maces。除了缓存,我还需要对数据重新排序,因为它们是异步获取的,没有顺序@BasSwinckelsevery文件由1000个块组成,共10米大小。正如您所说,我避免一次又一次地打开文件,因为IO操作非常昂贵。更重要的是,我需要按照正确的顺序对数据块重新排序每个文件由1000个块组成,总共10米大小。正如您所说,我避免一次又一次地打开文件,因为IO操作非常昂贵。更重要的是,在写入不同文件时,我需要按正确的顺序重新排列数据块,而不是冲突。你是说将响应保存到Redis这样的外部系统吗?它看起来更好,所以程序不需要维护非常大的数据数组。我将使用redid更新我的帖子,请检查!是的,您可以将其传递给redis,然后让工作人员检查redis中的数据并写入正确的文件。这样,您的web服务器将从文件IO中抽象出来,并且web服务器不会接触任何线程中的任何文件。就内存而言,这可以非常好地工作,因为这种抽象可以让您在不更改web服务器代码的情况下按指数级扩展。低耦合对于大型系统是好的,在较小的系统中,如我的系统,IMO并不十分重要。但我不知道采用Redis的最大优点是什么,也许最大的优点是更具可伸缩性,因为Redis是可伸缩的。写入不同的文件,而不是冲突。你的意思是将响应保存到像Redis这样的外部系统吗?它看起来更好,所以程序不需要维护非常大的数据数组。我将使用redid更新我的帖子,请检查!是的,您可以将其传递给redis,然后让工作人员检查redis中的数据并写入正确的文件。这样,您的web服务器将从文件IO中抽象出来,并且web服务器不会接触任何线程中的任何文件。就内存而言,这可以非常好地工作,因为这种抽象可以让您在不更改web服务器代码的情况下按指数级扩展。低耦合对于大型系统是好的,在较小的系统中,如我的系统,IMO并不十分重要。但我不知道是什么