我试图用Pygame和asyncio编写网络游戏,但我无法解决如何避免挂起读取问题。这是我的客户代码:
@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()
这挂在line = yield from reader.read(2**12)
行。我以前认为asyncio的意思是它是非阻塞的,所以如果没有任何数据要读取它就会继续执行。我现在看到的情况并非如此。
如何将asyncio网络代码与Pygame绘图和事件代码集成?
答案 0 :(得分:9)
yield from
的要点是将执行切换到asyncio的事件循环和以阻止当前协程,直到结果可用。要在不阻止当前协程的情况下安排任务,您可以使用asyncio.async()
。
在不阻止pygame循环的情况下打印读取数据:
@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
while
循环中不应该有阻塞调用。
read()
和sleep()
协同程序在同一个线程中并发运行(显然你也可以同时运行其他协同程序)。
答案 1 :(得分:7)
你可以"转换"将阻塞任务转换为非阻塞任务。
我建议:https://docs.python.org/3/library/asyncio-eventloop.html#executor。
我有一个功能,可以收听Twitter提要,功能"提及",然后我在执行程序中运行它,所以如果它挂起,它就不会阻止其他任务。
@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())
答案 2 :(得分:0)
因为您在调用read()后正试图读取'line'的值,所以您需要不惜任何代价获得该值...
如果协程不会因为没有数据而停止,那么如果'line'然后是None,你就可以在line.decode()调用上得到一个AttributeError。
您可以做的一件事是在阻塞调用上设置超时并处理超时异常:
...
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())
...