Как я могу проверить, если что-то читать в asyncio StreamReader в Windows и Python 3.7+? - PullRequest
0 голосов
/ 17 ноября 2018

Я пытаюсь связаться с Stockfish (это приложение stdin / stdout).

Работает так:

  1. Я посылаю какую-то строку в stdin.
  2. Он отвечает сразу несколькими строками в стандартный вывод.
  3. Может непрерывно отвечать следующими строками (оценка нового хода).
  4. Вяленая рыба никогда не должна останавливаться, поэтому communicate() не будет работать, так как не дизайнердля этого.add_reader не работает в Windows.

Он отправляет непредсказуемое количество строк и непрерывно.

Проблема заключается в том, что когда я вызываю await stdout.readline(), блокирует ли он выполнение программыне хотите блокировать поток, но проверьте, читается ли новая строка для чтения.Как я могу читать строки без блокировки.

Какой-то код, который я делаю - ничего сложного:

import asyncio

import sys


def stockfish_read_stdout(line):
    print(line)


async def run_stockfish():
    STOCKFISH_PATH = r'C:\root\chess\stockfish\stockfish 9\stockfish_9_x64_bmi2.exe'

    stockfish = await asyncio.subprocess.create_subprocess_exec(
        STOCKFISH_PATH,
        stdin=asyncio.subprocess.PIPE,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE)

    # It is maybe not work since output is not complete.
    stockfish.stdin.write('uci'.encode())

    # How to check if line read to read?
    # I put True but here should be check.
    while True:
        line = await stockfish.stdout.readline()
        print(line)

    await stockfish.wait()


if sys.platform == "win32":
    asyncio.set_event_loop_policy(
        asyncio.WindowsProactorEventLoopPolicy())

asyncio.run(run_stockfish(), debug=True)

Вывод:

Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD64)] on win32
runfile('C:/Users/Cezary Wagner/PycharmProjects/stockfish-proxy/sandbox/async_proxy/s01_async_stockfish.py', wdir='C:/Users/Cezary Wagner/PycharmProjects/stockfish-proxy/sandbox/async_proxy')
b'Stockfish 9 64 BMI2 by T. Romstad, M. Costalba, J. Kiiski, G. Linscott\r\n'

Но должно быть после uci:

Stockfish 9 64 BMI2 by T. Romstad, M. Costalba, J. Kiiski, G. Linscott
uci
id name Stockfish 9 64 BMI2
id author T. Romstad, M. Costalba, J. Kiiski, G. Linscott

option name Debug Log File type string default
option name Contempt type spin default 20 min -100 max 100
option name Threads type spin default 1 min 1 max 512
option name Hash type spin default 16 min 1 max 131072
option name Clear Hash type button
option name Ponder type check default false
option name MultiPV type spin default 1 min 1 max 500
option name Skill Level type spin default 20 min 0 max 20
option name Move Overhead type spin default 30 min 0 max 5000
option name Minimum Thinking Time type spin default 20 min 0 max 5000
option name Slow Mover type spin default 89 min 10 max 1000
option name nodestime type spin default 0 min 0 max 10000
option name UCI_Chess960 type check default false
option name SyzygyPath type string default 
option name SyzygyProbeDepth type spin default 1 min 1 max 100
option name Syzygy50MoveRule type check default true
option name SyzygyProbeLimit type spin default 6 min 0 max 6
uciok

1 Ответ

0 голосов
/ 10 декабря 2018

Вам необходимо создать отдельную сопрограмму, которая будет считывать строки из буфера стандартного вывода процесса, потому что await блокирует выполнение текущего сопрограммы до получения результата.

async def reader(process, msg_handler, exit_handler):
    while not process.stdout.at_eof():
        line = await process.stdout.readline()
        msg_handler(line.decode())
    # Finished
    exit_handler()

СейчасВы можете запустить его как задачу в цикле событий.

async def run_stockfish():
    STOCKFISH_PATH = r'C:\root\chess\stockfish\stockfish 9\stockfish_9_x64_bmi2.exe'

    stockfish = await asyncio.subprocess.create_subprocess_exec(
        STOCKFISH_PATH,
        stdin=asyncio.subprocess.PIPE,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE)

    # It is maybe not work since output is not complete.
    stockfish.stdin.write('uci\n'.encode())

    task = asyncio.create_task(reader(stockfish,
                                      lambda msg: print(f'Output: {msg}'),
                                      lambda: print('EOF'))

    # asyncio.create_task won't block this coroutine

Надеюсь, еще не поздно.

...