私は常にgeventを利用したクローラーのダウンロードページを持っています。クローラーはプロデューサー/コンシューマー パターンを採用しており、{method:get, url:xxxx, other_info:yyyy} のようなデータをキューにフィードします。
今、私はいくつかの応答をファイルにまとめたいと思っています。問題は、すべてのリクエストが終了したときに開いて書き込むことができず、コストがかかり、データが正しい順序になっていないことです。
すべての要求に番号を付け、応答を順番にキャッシュし、グリーンレットを開いてループしてファイルを組み立てる必要があると思います。疑似コードは次のようになります。
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 回のループが実行されます。
Update2
@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 に保存するのが良い考えかどうかは疑問です。さらなる提案を期待してください!