26

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 の描画およびイベント コードと統合するにはどうすればよいですか?

4

3 に答える 3

14

ポイントは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()同時に実行されます (明らかに、他のコルーチンも同時に実行できます)。

于 2014-12-29T00:49:56.313 に答える
0

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())
...
于 2015-06-15T18:04:06.263 に答える