我一直有一个 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
@IT Ninja 建议使用队列系统,所以我使用 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 中保存大数据是否是个好主意,希望有更多建议!