2015-01-23 2 views
7

Ich habe eine Funktion download_all, die durch eine fest codierte Liste von Seiten iteriert, um sie alle nacheinander herunterzuladen. Aber wenn ich die Liste basierend auf den Ergebnissen einer Seite dynamisch hinzufügen möchte, wie kann ich das tun? Laden Sie beispielsweise die erste Seite herunter, parsen Sie sie und fügen Sie basierend auf den Ergebnissen andere zur Ereignisschleife hinzu.Dynamisch zur Liste hinzufügen, was die Ereignisschleife von Python asyncio ausführen soll

@asyncio.coroutine 
def download_all(): 
    first_page = 1 
    last_page = 100 
    download_list = [download(page_number) for page_number in range(first_page, last_page)] 
    gen = asyncio.wait(download_list) 
    return gen 

if __name__ == '__main__': 
    loop = asyncio.get_event_loop() 
    futures = loop.run_until_complete(download_all()) 

Antwort

1

Bitte werfen Sie einen Blick auf Web Crawler example.

Es verwendet asyncio.JoinableQueue Warteschlange zum Speichern von URLs für Fetch-Aufgaben, sondern demonstrieren viele nützliche Techniken auch.

+2

Es wäre schön, wenn Sie ein aktuelles Beispiel hier und dann diese eine referenzierte gab. – KronoS

+0

Das Beispiel ist größer als üblich SO. Ich bezweifle, dass es sich lohnt, hierher geschoben zu werden. –

2

Eine Möglichkeit, dies zu erreichen, ist die Verwendung einer Warteschlange.

#!/usr/bin/python3 

import asyncio 

try: 
    # python 3.4 
    from asyncio import JoinableQueue as Queue 
except: 
    # python 3.5 
    from asyncio import Queue 

@asyncio.coroutine 
def do_work(task_name, work_queue): 
    while not work_queue.empty(): 
     queue_item = work_queue.get_nowait() 

     # simulate condition where task is added dynamically 
     if queue_item % 2 != 0: 
      work_queue.put_nowait(2) 
      print('Added additional item to queue') 

     print('{0} got item: {1}'.format(task_name, queue_item)) 
     yield from asyncio.sleep(queue_item) 
     print('{0} finished processing item: {1}'.format(task_name, queue_item)) 

if __name__ == '__main__': 

    queue = Queue() 

    # Load initial jobs into queue 
    [queue.put_nowait(x) for x in range(1, 6)] 

    # use 3 workers to consume tasks 
    taskers = [ 
     do_work('task1', queue), 
     do_work('task2', queue), 
     do_work('task3', queue) 
    ] 

    loop = asyncio.get_event_loop() 
    loop.run_until_complete(asyncio.wait(taskers)) 
    loop.close() 

eine Warteschlange von asyncio Sie verwenden können sicherstellen, dass die „Einheiten“ der Arbeit von den Aufgaben/Futures getrennt sind, die zunächst auf asyncio der Ereignisschleife gegeben. Im Grunde erlaubt dies die Hinzufügung zusätzlicher "Einheiten" von Arbeit unter bestimmten Bedingungen.

Beachten Sie, dass in dem obigen Beispiel Aufgaben mit gerader Nummer terminal sind, sodass keine zusätzliche Aufgabe hinzugefügt wird, wenn dies der Fall ist. Dies führt schließlich zum Abschluss aller Aufgaben, aber in Ihrem Fall könnten Sie leicht eine andere Bedingung verwenden, um zu bestimmen, ob ein anderes Element zur Warteschlange hinzugefügt wird oder nicht.

Ausgang:

Added additional item to queue 
task2 got item: 1 
task1 got item: 2 
Added additional item to queue 
task3 got item: 3 
task2 finished processing item: 1 
task2 got item: 4 
task1 finished processing item: 2 
Added additional item to queue 
task1 got item: 5 
task3 finished processing item: 3 
task3 got item: 2 
task3 finished processing item: 2 
task3 got item: 2 
task2 finished processing item: 4 
task2 got item: 2 
task1 finished processing item: 5 
task3 finished processing item: 2 
task2 finished processing item: 2 
+0

In diesem Fall müssen Sie 'asyncio.Queue' nicht verwenden, da Sie ohnehin nicht die Coroutine-Methode verwenden. Gewöhnliche "Liste" wird tun: https://gist.github.com/452f9a9f385e1d839309f76bb421ae3c – azag0

Verwandte Themen