【问题标题】:How can I check if something to read in asyncio StreamReader in Windows and Python 3.7+?如何检查 Windows 和 Python 3.7+ 中的 asyncio StreamReader 中是否有要读取的内容?
【发布时间】:2018-11-17 11:35:39
【问题描述】:

我尝试与 Stockfish 通信(它是标准输入/标准输出应用程序)。

它是这样工作的:

  1. 我向标准输入发送了一些行。
  2. 它会立即响应一些行到标准输出中。
  3. 它可以连续响应下一行(新移动评估)。
  4. Stockfish 永远不会停止,所以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)

输出是:

Win32 上的 Python 3.7.1(v3.7.1:260ec2c36a,2018 年 10 月 20 日,14:57:15)[MSC v.1915 64 位(AMD64)] 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,作者 T. Romstad、M. Costalba、J. Kiiski、G. Linscott\r\n'

但应该在uci之后:

Stockfish 9 64 BMI2,作者 T. Romstad、M. Costalba、J. Kiiski、G. Linscott uci id 名称 Stockfish 9 64 BMI2 ID 作者 T. Romstad、M. Costalba、J. Kiiski、G. Linscott 选项名称调试日志文件类型字符串默认值 选项名称 蔑视类型 自旋 默认 20 分钟 -100 最大 100 选项名称 线程类型 spin default 1 min 1 max 512 选项名称 散列类型 自旋 默认 16 min 1 max 131072 选项名称清除哈希类型按钮 选项名称 考虑类型检查 默认 false 选项名称 MultiPV 类型 spin 默认 1 min 1 max 500 选项名称 技能等级 类型 spin 默认 20 min 0 max 20 选项名称 Move Overhead 类型 spin 默认 30 min 0 max 5000 选项名称 最小思考时间 类型 spin 默认 20 min 0 max 5000 选项名称 Slow Mover 类型 spin default 89 min 10 max 1000 选项名称节点时间类型自旋默认值 0 min 0 max 10000 选项名称 UCI_Chess960 类型检查 默认 false 选项名称 SyzygyPath 类型字符串 默认 选项名称 SyzygyProbeDepth 类型 spin default 1 min 1 max 100 选项名称 Syzygy50MoveRule 类型检查 默认 true 选项名称 SyzygyProbeLimit 类型 spin default 6 min 0 max 6 优克

【问题讨论】:

  • 应该'uci'.encode()'uci\n'.encode() 还是更简单的b'uci\n'
  • 可能是,但我不确定所以不是我不使用我会检查。

标签: python python-asyncio python-3.7


【解决方案1】:

您需要创建一个单独的协程,该协程将从进程的标准输出缓冲区中读取行,因为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

希望还不算太晚。

【讨论】:

  • 我需要测试它看起来很有希望。
  • @Chameleon 如果它适合您,请您将其标记为正确答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多