Nieblokujące we / wy z asyncio
[[2]] staram się napisać grę sieciową z Pygame i asyncio, ale nie potrafię wymyślić, jak uniknąć zawieszania się na czytaniu. Oto Mój kod dla klienta:
@asyncio.coroutine
def handle_client():
print("Connected!")
reader, writer = yield from asyncio.open_connection('localhost', 8000)
while True:
mouse_up = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONUP:
mouse_up = True
if mouse_up:
print("Writing")
writer.write(b"Mouse up")
print("Waiting to read")
line = yield from reader.read(2**12)
print(line.decode())
writer.close()
To wisi na linii line = yield from reader.read(2**12)
. Wcześniej myślałem, że asyncio chodzi o to, że nie blokuje, a więc jeśli nie ma żadnych danych do odczytu, to po prostu kontynuuje wykonywanie. Teraz widzę, że tak nie jest.
Jak zintegrować kod sieciowy asyncio z rysunkiem Pygame i eventem kod?
3 answers
Punktem yield from
jest przełączenie wykonania na pętlę zdarzeń asyncio i, aby zablokować bieżącą koronę, dopóki wynik nie będzie dostępny. Aby zaplanować zadanie bez blokowania bieżącego coroutine, możesz użyć asyncio.async()
.
@asyncio.coroutine
def read(reader, callback):
while True:
data = yield from reader.read(2**12)
if not data: # EOF
break
callback(data)
@asyncio.coroutine
def echo_client():
reader, ...
chunks = []
asyncio.async(read(reader, chunks.append))
while True:
pygame.event.pump() # advance pygame event loop
...
if chunks: # print read-so-far data
print(b''.join(chunks).decode())
del chunks[:]
yield from asyncio.sleep(0.016) # advance asyncio loop
Nie powinno być blokowania połączeń wewnątrz pętli while
.
read()
i sleep()
koroutiny działają jednocześnie w tym samym wątku (oczywiście można uruchomić inne koroutiny jednocześnie też).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-29 11:50:18
Możesz "przekształcić" zadanie blokujące w nieblokujące.
Proponuję: https://docs.python.org/3/library/asyncio-eventloop.html#executor .
Mam funkcję, która nasłuchuje kanału na Twitterze, funkcję "wzmiankę" i uruchamiam ją w executorze, więc jeśli się zawiesi, nie blokuje innych zadań.
@asyncio.coroutine
def boucle_deux():
#faire attendre la boucle si pas bcp de mots
while True:
print("debut du deux")
value = t.next()
future2 = loop.run_in_executor(None, mention, "LQNyL2xvt9OQMvje7jryaHkN8",
"IRJX6S17K44t8oiVGCjrj6XCVKqGSX9ClfpGpfC467rajqePGb",
"2693346740-km3Ufby8r9BbYpyzcqwiHhss22h4YkmnPN4LnLM",
"53R8GAAncFJ1aHA1yJe1OICfjqUbqwcMR38wSqvbzsQMB", 23, value)
response2 = yield from future2
yield from asyncio.sleep(5)
print("fin du deux")
asyncio.Task(boucle_deux())
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-03 17:25:18
Cóż, ponieważ próbujesz odczytać wartość 'line' zaraz po wywołaniu read (), potrzebujesz tej wartości za wszelką cenę...
Jeśli coroutine nie zatrzyma się, ponieważ nie ma danych, możesz uzyskać AttributeError na linii.decode () wywołanie if 'line' then is None.
Jedną z rzeczy, które możesz zrobić, to ustawić limit czasu na wywołanie blokujące i obsłużyć wyjątek timeout:
...
print("Waiting to read")
try: # block at most for one second
line = yield from asyncio.wait_for(reader.read(2**12), 1)
except asyncio.TimeoutError:
continue
else:
print(line.decode())
...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-15 18:04:06