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の描画およびイベントコードと統合するにはどうすればよいですか?
_yield from
_のポイントは、実行をasyncioのイベントループに切り替えることですand結果が利用可能になるまで、現在のコルーチンをブロックします。現在のコルーチンをブロックせずにタスクをスケジュールするには、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()
コルーチンは、同じスレッドで同時に実行されます(もちろん、他のコルーチンも同時に実行できます)。
ブロッキングタスクを非ブロッキングタスクに「変換」できます。
私はこれを提案します: 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())
read()を呼び出した直後に「line」の値を読み取ろうとしているので、どんな犠牲を払ってもその値が必要です...
データがないためにコルーチンが停止しない場合、「line」がNoneの場合、line.decode()呼び出しでAttributeErrorが発生する可能性があります。
実行できることの1つは、ブロッキング呼び出しにタイムアウトを設定し、タイムアウト例外を処理することです。
...
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())
...