2017-04-14 1 views
0

Stochern nur meine Zehe in asynchrone Programmierung in Python, und lief in eine interessante Anwendung für die ich Dateigrößen auf etwa 10 Dateien auf ~ 100 Maschinen sammeln müssen, um zu sehen, welche Maschinen Aren sind Log-Dateien nicht korrekt löschen.Async Coroutine scheint nicht zu Ende

Mein synchroner Ansatz war:

File_info = namedtuple("File_info", "machineinfo size") 

machines = utils.list_machines() # the computers being queried 
# each machine object has attributes like "name", "IP", and "site_id" among others 

file_sizes = {} 
# {filename: [File_info, ...], ...} 

for m in machines: 
    print(f"Processing {m}...") # this is "Processing {m}...".format(m=m) 
           # isn't Python 3.6 awesome?! 
    for path in glob.glob(f"//{m.IP}/somedir/*.dbf"): 
     fname = os.path.split(path)[-1].lower() 
     machineinfo = (m.site_id, m.name) 
     size = os.stat(path).st_size 
     file_sizes.setdefault(fname, []).append(File_info(registerinfo, size)) 

Dies funktioniert gut, aber dauert eine lange Zeit mit den Netzwerk-Operationen all diese Klecksen und Statistiken zu ziehen. Ich wollte die async/await-Syntax von Python 3.5 mit asyncio verwenden, um diese Aufrufe zu asynchronisieren. Hier ist, was ich kam mit:

File_info = namedtuple("File_info", "machineinfo size") 

machines = utils.list_machines() 

file_sizes = {} 
# {filename: [File_info, ...], ...} 

async def getfilesizes(machine, loop): 
    machineinfo = machine.site_id, machine.name 
    paths = glob.glob(f"//{machine.IP}/somedir/*.dbf") 
    coros = [getsize(path) for path in paths] 
    results = loop.run_until_complete(asyncio.gather(*coros)) 
    sizes = {fname: File_info(machineinfo, size) for (fname, size) in results} 
    return sizes 

async def getsize(path): 
    return os.path.split(path)[-1], os.stat(path).st_size 

loop = asyncio.get_event_loop() 
results = loop.run_until_complete(asyncio.gather(*(getfilesizes(m, loop) for m in machines))) 
for result in results: 
    file_sizes.update(result) 
    # I have a problem here since my dict values are lists that need to extend 
    # not overwrite, but that's not relevant for the error I'm getting 

jedoch das Skript innerhalb des äußeren loop.run_until_complete Abschnitt hängt. Was mache ich falsch?

+0

Eine Coroutine, die eine andere Coroutine ausführen oder das Ergebnis einer Zukunft erhalten will, soll sie "erwarten", nicht mit "run_until_complete" abliefern. – user2357112

+0

Soll ich auf asyncio.gather (...) warten? –

+0

@ user2357112 Nun, ich werde ein Affe Onkel sein, das war einfach. Ich bin mir nicht sicher, warum ich die Verbindung nicht hergestellt habe, dass "asyncio.gather" ein "Future" -Objekt gibt, damit ich es einfach wegstellen kann, anstatt es zu planen. Möchten Sie das als Antwort aufschreiben? Sonst antworte ich selbst. –

Antwort

0

Eine Coroutine, die eine andere Coroutine ausführen möchte (wie getfilesizes tut mit getsize) sollte await es lieber als in der Ereignisschleife planen.

... 

async def getfilesizes(machine): # changed func sig 
    machineinfo = machine.site_id, machine.name 
    paths = glob.glob(f"//{machine.IP}/somedir/*.dbf") 
    coros = [getsize(path) for path in paths] 
    results = await asyncio.gather(*coros) # await the results instead! 
    sizes = {fname: File_info(machineinfo, size) for (fname, size) in results} 
    return sizes 

... 

Seit asyncio.gather schafft eine Zukunft aus einer beliebigen Anzahl von Koroutinen, diese await funktionell wirkt auf die ganze Gruppe von Koroutinen und packt alle Ergebnisse auf einmal.

Verwandte Themen