异步延迟 StreamReader.read
asyncio delayed StreamReader.read
我对 asyncio 和 async def/await 语法有点陌生,所以我想问一下我应该如何做这样的事情:
import asyncio
import pygame
import logging
from pygame import *
log = logging.getLogger('')
class Client:
def __init__(self, host, port):
self.host = host
self.port = port
self.loop = asyncio.get_event_loop()
self.loop.run_until_complete(self.create_client())
async def create_client(self):
self.reader, self.writer = await asyncio.open_connection(self.host,
self.port,
loop=self.loop)
asyncio.ensure_future(self._handle_packets(), loop=self.loop)
async def _handle_packets(self):
while True:
data = await self.reader.read(4096)
if not data:
continue
message = data.decode()
log.debug("(NET) Received "+message)
def send(self, data):
self.loop.run_until_complete(asyncio.ensure_future(self._send(data),
loop=self.loop))
async def _send(self, data):
self.writer.write(data)
await self.writer.drain()
print("_send done")
def disconnect(self):
print("DC")
self.loop.close()
def main():
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Pyond client")
bg = Surface((640, 480))
bg.fill(Color("#004400"))
client = Client('127.0.0.1', 2508)
while True:
pygame.event.pump()
for e in pygame.event.get():
if e.type == QUIT:
raise SystemExit
elif e.type == KEYUP:
if e.key == K_UP:
client.send(b"{'Hello':'World'}")
screen.blit(bg, (0, 0))
pygame.display.update()
client.disconnect()
if __name__ == "__main__":
main()
此代码使用 pygame 创建 640x480 window,然后读取传入的 K_UP(向上箭头)键。按下后,向服务器发送类似 json 的字符串。 _handle_packets
应该从服务器读取任何传入数据并打印出来。
我正在测试这段代码并且发送工作正常,但接收很延迟。我确定我需要将处理程序放在其他地方,那么具体在哪里呢?
顺便说一句, send 只工作一次。这方面也需要帮助。
这里有几个问题。
第一个漂亮基础。 asycnio
事件循环在 create_client()
完成后停止 运行ning,只有 运行s 再次 而 你 send()
数据.因此,它唯一能够 运行 _handle_packets
的时间是当您 send()
ing 时。理想情况下,您应该在更高范围内启动一次事件循环,并在完成所有操作后关闭它。
第二个问题是,每当您 client.send(b"{'Hello':'World'}")
,您将阻塞外部 pygame
while True
循环,阻止任何其他事件被处理,直到前一个事件被发送。您应该使用 asyncio.Queue
将事件排队并从 Client
class.
发送它们
以下是我要进行的一些更改(抱歉,未经测试;我没有 pygame
安装 ATM):
# vim: tabstop=4 expandtab
import asyncio
import pygame
import logging
from pygame import *
log = logging.getLogger('')
class Client:
def __init__(self, host, port, loop):
self.host = host
self.port = port
self.loop = loop
self.send_q = asyncio.Queue()
async def connect(self):
self.reader, self.writer = await asyncio.open_connection(self.host,
self.port,
loop=self.loop)
self.loop.create_task(self._handle_packets())
self.loop.create_task(self._send())
async def _handle_packets(self):
while True:
data = await self.reader.read(4096)
if not data:
continue
message = data.decode()
log.debug("(NET) Received "+message)
def send(self, data):
self.send_q.put_nowait(data)
async def _send(self):
while True:
data = await self.send_q.get()
self.writer.write(data)
await self.writer.drain()
def disconnect(self):
print("DC")
self.writer.close()
async def main(loop):
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Pyond client")
bg = Surface((640, 480))
bg.fill(Color("#004400"))
client = Client('127.0.0.1', 2508, loop)
await client.connect()
while True:
pygame.event.pump()
for e in pygame.event.get():
if e.type == QUIT:
raise SystemExit
elif e.type == KEYUP:
if e.key == K_UP:
client.send(b"{'Hello':'World'}")
screen.blit(bg, (0, 0))
pygame.display.update()
client.disconnect()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
loop.close()
另一个重要要记住的是,你不应该用pygame
阻塞asyncio
事件循环,否则Client
后台的网络处理将停止。我从未使用过 pygame
,所以我不熟悉哪个 pygame
函数可能是 "blocking",但应该使用 result = await loop.run_in_executor(None, blocking_func, *func_args)
来调用它们。这将在另一个线程中调用阻塞函数。
我对 asyncio 和 async def/await 语法有点陌生,所以我想问一下我应该如何做这样的事情:
import asyncio
import pygame
import logging
from pygame import *
log = logging.getLogger('')
class Client:
def __init__(self, host, port):
self.host = host
self.port = port
self.loop = asyncio.get_event_loop()
self.loop.run_until_complete(self.create_client())
async def create_client(self):
self.reader, self.writer = await asyncio.open_connection(self.host,
self.port,
loop=self.loop)
asyncio.ensure_future(self._handle_packets(), loop=self.loop)
async def _handle_packets(self):
while True:
data = await self.reader.read(4096)
if not data:
continue
message = data.decode()
log.debug("(NET) Received "+message)
def send(self, data):
self.loop.run_until_complete(asyncio.ensure_future(self._send(data),
loop=self.loop))
async def _send(self, data):
self.writer.write(data)
await self.writer.drain()
print("_send done")
def disconnect(self):
print("DC")
self.loop.close()
def main():
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Pyond client")
bg = Surface((640, 480))
bg.fill(Color("#004400"))
client = Client('127.0.0.1', 2508)
while True:
pygame.event.pump()
for e in pygame.event.get():
if e.type == QUIT:
raise SystemExit
elif e.type == KEYUP:
if e.key == K_UP:
client.send(b"{'Hello':'World'}")
screen.blit(bg, (0, 0))
pygame.display.update()
client.disconnect()
if __name__ == "__main__":
main()
此代码使用 pygame 创建 640x480 window,然后读取传入的 K_UP(向上箭头)键。按下后,向服务器发送类似 json 的字符串。 _handle_packets
应该从服务器读取任何传入数据并打印出来。
我正在测试这段代码并且发送工作正常,但接收很延迟。我确定我需要将处理程序放在其他地方,那么具体在哪里呢?
顺便说一句, send 只工作一次。这方面也需要帮助。
这里有几个问题。
第一个漂亮基础。 asycnio
事件循环在 create_client()
完成后停止 运行ning,只有 运行s 再次 而 你 send()
数据.因此,它唯一能够 运行 _handle_packets
的时间是当您 send()
ing 时。理想情况下,您应该在更高范围内启动一次事件循环,并在完成所有操作后关闭它。
第二个问题是,每当您 client.send(b"{'Hello':'World'}")
,您将阻塞外部 pygame
while True
循环,阻止任何其他事件被处理,直到前一个事件被发送。您应该使用 asyncio.Queue
将事件排队并从 Client
class.
以下是我要进行的一些更改(抱歉,未经测试;我没有 pygame
安装 ATM):
# vim: tabstop=4 expandtab
import asyncio
import pygame
import logging
from pygame import *
log = logging.getLogger('')
class Client:
def __init__(self, host, port, loop):
self.host = host
self.port = port
self.loop = loop
self.send_q = asyncio.Queue()
async def connect(self):
self.reader, self.writer = await asyncio.open_connection(self.host,
self.port,
loop=self.loop)
self.loop.create_task(self._handle_packets())
self.loop.create_task(self._send())
async def _handle_packets(self):
while True:
data = await self.reader.read(4096)
if not data:
continue
message = data.decode()
log.debug("(NET) Received "+message)
def send(self, data):
self.send_q.put_nowait(data)
async def _send(self):
while True:
data = await self.send_q.get()
self.writer.write(data)
await self.writer.drain()
def disconnect(self):
print("DC")
self.writer.close()
async def main(loop):
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Pyond client")
bg = Surface((640, 480))
bg.fill(Color("#004400"))
client = Client('127.0.0.1', 2508, loop)
await client.connect()
while True:
pygame.event.pump()
for e in pygame.event.get():
if e.type == QUIT:
raise SystemExit
elif e.type == KEYUP:
if e.key == K_UP:
client.send(b"{'Hello':'World'}")
screen.blit(bg, (0, 0))
pygame.display.update()
client.disconnect()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
loop.close()
另一个重要要记住的是,你不应该用pygame
阻塞asyncio
事件循环,否则Client
后台的网络处理将停止。我从未使用过 pygame
,所以我不熟悉哪个 pygame
函数可能是 "blocking",但应该使用 result = await loop.run_in_executor(None, blocking_func, *func_args)
来调用它们。这将在另一个线程中调用阻塞函数。