1

私は常に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 に保存するのが良い考えかどうかは疑問です。さらなる提案を期待してください!

4

2 に答える 2

1

このようなものは、各スレッドが独自のファイル ハンドラーを持つ代わりに、キュー システムで処理する方が適切な場合があります。これは、各スレッドが独自のハンドラーを持つため、このファイルを書き込むときに競合状態に陥る可能性があるためです。

リソースに関する限り、ファイルに渡される情報が極端に大きくないと仮定すると、これはディスク書き込み以外のリソースをあまり消費しないはずです (Python はこれについて非常に優れています)。ただし、これが問題を引き起こす場合は、ファイルのアップロードのオプションとして利用できる限り、ファイルをチャンクでメモリに読み込む (そしてチャンクに比例して書き込む) ことで、この問題を大幅に軽減できます。

于 2013-11-07T15:30:12.953 に答える
0

データのサイズによって異なります。非常に大きい場合、メモリ内にすべての構造を持つプログラムの速度が低下する可能性があります。

メモリに問題がない場合は、ファイルから常に読み取るのではなく、構造をメモリに保持する必要があります。並行リクエストでファイルを何度も開くことは、良い解決策ではありません。

于 2013-11-07T15:28:55.397 に答える