2017-02-20 76 views
25

Mam problemy ze zrozumieniem użycia asynchronicznego zrozumienia wprowadzonego w Pythonie 3.6. Jako zrzeczenie się, nie mam dużego doświadczenia w zajmowaniu się ogólnie kodem asynchronicznym w Pythonie.Python Asynchronous Comprehensions - jak działają?

Przykład podany w dokumencie what's new for Python 3.6 jest:

result = [i async for i in aiter() if i % 2] 

W PEP, to jest rozszerzona do:

result = [] 
async for i in aiter(): 
    if i % 2: 
     result.append(i) 

myślę Rozumiem, że funkcja aiter() jest wywoływana asynchronicznie, aby każda iteracja z aiter mogła przebiegać bez poprzedniej koniecznie powracającej jeszcze (lub czy to zrozumienie jest złe?).

To, czego nie jestem pewien, to sposób, w jaki przekłada się tutaj na zrozumienie listy. Czy wyniki zostaną umieszczone na liście w kolejności, w jakiej są zwracane? Czy istnieją skuteczne "placeholder" na liście końcowej, aby każdy wynik został umieszczony na liście we właściwej kolejności? Czy też myślę o tym w niewłaściwy sposób?

Dodatkowo, czy ktoś jest w stanie dostarczyć rzeczywistego przykładu, który zilustrowałby zarówno odpowiedni przypadek użycia, jak i podstawową mechanikę async w takich rozumowaniach?

+0

Ciekawi mnie również generator asynchroniczny. To samo zachowanie lub inne? –

Odpowiedz

16

Zasadniczo pytasz, jak działa pętla async for w zwykłej pętli. To, że możesz teraz używać takiej pętli w zrozumieniu listy, nie robi tutaj żadnej różnicy; to tylko optymalizacja, która pozwala uniknąć powtarzających się wywołań list.append(), dokładnie tak, jak robi to normalne rozumienie list.

Pętla async for czeka na każdy kolejny krok protokołu iteracyjnego, w którym zablokowana byłaby regularna pętla for.

Aby zilustrować wyobrazić normalnego for pętli:

for foo in bar: 
    ... 

Do tej pętli Python zasadniczo działa następująco:

bar_iter = iter(bar) 
while True: 
    try: 
     foo = next(bar_iter) 
    except StopIteration: 
     break 
    ... 

next(bar_iter) połączenie nie jest asynchroniczne; blokuje się.

Teraz zastąpić for z async for, a co Python robi zmiany:

bar_iter = aiter(bar) # aiter doesn't exist, but see below 
while True: 
    try: 
     foo = await anext(bar_iter) # anext doesn't exist, but see below 
    except StopIteration: 
     break 
    ... 

W powyższym przykładzie aiter() i anext() funkcje są fikcyjne; są one funkcjonalnie dokładnymi odpowiednikami ich braci, ale zamiast __iter__ i __next__, te zastosowania wykorzystują __aiter__ i . Oznacza to, że asynchroniczne przechwyty istnieją dla tej samej funkcjonalności, ale różnią się od ich asynchronicznych wariantów prefiksem a.

await kluczowe istnieje zasadnicza różnica, więc dla każdej iteracji an async for plony pętli sterowania, aby inni współprogram może działać zamiast.

Ponownie, w celu ponownej iteracji, wszystko to zostało już dodane w Pythonie 3.5 (patrz PEP 492), wszystko co nowe w Pythonie 3.6 jest takie, że możesz użyć takiej pętli także w zrozumieniu list. I w wyrażeniach generatora oraz ustaleniach i dyktowaniu, o to chodzi.

Last but not least, ten sam zestaw zmian pozwoliły również użyć await <expression> w sekcji ekspresji w zrozumieniu, więc:

[await func(i) for i in someiterable] 

jest teraz możliwe.

+0

Dzięki Martijn za szczegółową odpowiedź. Tak więc pętla 'asynchronizująca dla' zachowuje się tak samo jak normalna pętla' for', z tą różnicą, że kontrola iteracji pętli jest przekazywana do otaczającego curouta? Będę musiał poprawnie przejrzeć użycie coroutines, ale to ma dużo więcej sensu. –

10

myślę Rozumiem, że funkcja jest wywoływana asynchronicznie aiter(), tak że każda iteracja aiter może przebiegać bez poprzedni koniecznie powrocie jeszcze (albo jest to zrozumienie źle?).

To zrozumienie jest złe. Iteracje pętli async for nie mogą być wykonywane równolegle. async for jest sekwencyjny jak zwykła pętla for.

Asynchroniczna część async for polega na tym, że umożliwia iteratorowi await w imieniu iterującego go coroutine. Jest przeznaczony tylko do użytku w asynchronicznych programach i tylko do użytku w specjalnych asynchronicznych iterabelach. Poza tym, jest to w większości podobne do regularnej pętli for.

+0

Dzięki, wydaje mi się, że potrzebowałem pójść i właściwie zrozumieć coroutines, zanim spróbuję obejść się przy użyciu 'async'. Doceniam poprawkę. :) –