4

Web サイトからデータを取得し、結果をデータベースにダンプする Python 2.7 プログラムがあります。コンシューマ プロデューサー モデルに従い、threading モジュールを使用して記述されています。

楽しみのために、新しいasyncioモジュール (3.4 以降)を使用してこのプログラムを書き直したいのですが、これを適切に行う方法がわかりません。

最も重要な要件は、プログラムが同じ Web サイトから順番にデータを取得する必要があることです。たとえば、' http://a-restaurant.com 'という URL の場合、最初に' http://a-restaurant.com/menu/0 'を取得し、次に' http://a-restaurant.com/menu/ ' を取得する必要があります。 1 '、次に' http://a-restaurant.com/menu/2 '、... 順番にフェッチされない場合、Web サイトはページの配信を完全に停止し、0 から開始する必要があります。

ただし、別の Web サイト ( 「http://another-restaurant.com ) の別のフェッチは、同時に実行できます (実行する必要があります) (他のサイトにも順次制限があります)。

threading モジュールは、Web サイトごとに個別のスレッドを作成でき、各スレッドで 1 つのページの読み込みが完了するまで待ってから別のページを取得できるため、これに適しています。

これは、スレッド化バージョン (Python 2.7) から大幅に簡略化されたコード スニペットです。

class FetchThread(threading.Threading)
    def __init__(self, queue, url)
        self.queue = queue
        self.baseurl = url
    ...
    def run(self)
        # Get 10 menu pages in a sequantial order
        for food in range(10):
            url = self.baseurl + '/' + str(food)
            text = urllib2.urlopen(url).read()
            self.queue.put(text)
            ...
def main()
    queue = Queue.Queue()
    urls = ('http://a-restaurant.com/menu', 'http://another-restaurant.com/menu')
    for url in urls:
        fetcher = FetchThread(queue, url)
        fetcher.start()
        ...

そして、これが私がasyncioでそれをやろうとした方法です(3.4.1で):

@asyncio.coroutine
def fetch(url):
    response = yield from aiohttp.request('GET', url)
    response = yield from response.read_and_close()
    return response.decode('utf-8')

@asyncio.coroutine
def print_page(url):
    page = yield from fetch(url)
    print(page)


l = []
urls = ('http://a-restaurant.com/menu', 'http://another-restaurant.com/menu')
for url in urls:
    for food in range(10):
        menu_url = url + '/' + str(food)
        l.append(print_page(menu_url))

loop.run_until_complete(asyncio.wait(l))

そして、すべてを順不同でフェッチして出力します。まあ、それがそれらのコルーチンの全体的なアイデアだと思います。aiohttp を使用せずに urllib でフェッチする必要がありますか? しかし、最初のレストランのフェッチは、他のレストランのフェッチをブロックしますか? 私はこれを完全に間違って考えているだけですか?(これは、順番に取得するための単なるテストです。キューの部分にはまだ到達していません。)

4

2 に答える 2

2

asyncio.Taskasyncio worldの代替threading.Threadです。 また、新しいタスクを作成します。asyncio.async

asyncio.gatherは、複数のコルーチンを待機する非常に便利な方法ですasyncio.wait

@asyncio.coroutine
def fetch(url):
    response = yield from aiohttp.request('GET', url)
    response = yield from response.read_and_close()
    return response.decode('utf-8')

@asyncio.coroutine
def print_page(url):
    page = yield from fetch(url)
    print(page)

@asyncio.coroutine
def process_restaurant(url):
    for food in range(10):
        menu_url = url + '/' + str(food)
        yield from print_page(menu_url)

urls = ('http://a-restaurant.com/menu', 'http://another-restaurant.com/menu')
coros = []
for url in urls:
    coros.append(asyncio.Task(process_restaurant(url)))

loop.run_until_complete(asyncio.gather(*coros))
于 2014-06-17T08:46:24.897 に答える