簡體   English   中英

通過“子進程”將數據傳遞給“stdin”時,“stdout”為空,但手動輸入輸入時包含預期的 output?

[英]`stdout` is empty when passing data to `stdin` via `subprocess`, but contains the expected output when input is entered manually?

所以我正在努力嘗試從 Leela Chess Zero 引擎接收國際象棋移動數據。 我已經完成了所有 UI 和后端的其他部分,這是我需要實現的最后一件事。 不幸的是,我似乎高估了 Python 中子處理的簡單程度......

為了解釋更多背景,我需要做的就是:

  1. 在本地目錄中調用/運行lc0.exe 我處理得很好。
  2. 通過命令position startpos e2e4 e7e5 e1e2 , go nodes 100 ,按順序通過標准輸入quit 根據我可以通過 stderr 衡量的內容,這似乎也可以正常工作。
  3. 接收/讀取標准輸出。 這就是我卡住的地方。

這是我到目前為止嘗試過的事情:

>>> from subprocess import Popen, PIPE, STDOUT
>>> p = Popen(['lc0'], stdout=PIPE, stdin=PIPE, stderr=PIPE)
>>> stdout_data = p.communicate(input=b'position startpos e2e4 e7e5 e1e2\ngo nodes 100\nquit')[0]
>>> stdout_data
b''

我得到一個空字節字符串。 然后我嘗試了另一種方法作為測試:

>>> import subprocess
>>> subprocess.check_output(['lc0'], stderr=PIPE) #the following 3 lines is me typing into stdin
position startpos e2e4 e7e5 e1e2
go nodes 100
quit
b'info depth 1 seldepth 2 time 4081 nodes 4 score cp 12 nps 133 tbhits 0 pv e2e4 c7c5\r\ninfo depth 2 seldepth 3 time 4116 nodes 11 score cp 13 nps 166 tbhits 0 pv e2e4 c7c5 g1f3\r\ninfo depth 3 seldepth 4 time 4151 nodes 25 score cp 13 nps 247 tbhits 0 pv e2e4 c7c5 g1f3 e7e6\r\ninfo depth 3 seldepth 5 time 4218 nodes 68 score cp 13 nps 407 tbhits 0 pv e2e4 c7c5 b1c3 b8c6 g1e2\r\ninfo depth 4 seldepth 6 time 4312 nodes 134 score cp 13 nps 513 tbhits 0 pv e2e4 c7c5 b1c3 b8c6 g1f3 e7e5\r\nbestmove e2e4 ponder c7c5\r\n'

尤里卡。 我從標准輸出收到了正確的 output: 現在是時候以編程方式進行操作了:

>>> subprocess.check_output(['lc0'], stderr=PIPE, input=b'position startpos e2e4 e7e5 e1e2\ngo nodes 100\nquit')
b''

混蛋? 這里發生了什么? 我可以通過刪除stderr=PIPE參數來確認所有命令顯然確實是由引擎運行的,但是當一切都說完之后,當我以編程方式傳遞命令時,stdout 是空的。 我也嘗試過使用subprocess.stdin.write()得到相同的結果。

經過大量挖掘,我發現pexpect可能更適合這個用例。 我安裝了pip install wexpect and lo' 並且看:

>>> from wexpect import spawn
>>> child = spawn("lc0")

...

是的,它只是掛起。 打破 ^C 給了我異常pywintypes.error: (2, 'CreateFile', 'The system cannot find the file specified.') ,所以我可以理解地對使用pexpect而不是subprocess不太自信,因為我似乎更接近后者的解決方案。

無論如何,我確信我以某種方式濫用subprocess ,但我到底做錯了什么? 為什么我在手動通過stdin傳遞命令時正確接收stdout ,但在使用input=參數時卻沒有?

我們可以使用 stdin.write() 一次向引擎發送一個命令。 還正確發送 position 命令, moves如下: position startpos moves m1, m2...安全退出引擎並正確終止進程。

代碼

from subprocess import Popen, PIPE, STDOUT, TimeoutExpired


def ecommand(p, comm):
    p.stdin.write(f'{comm}\n')


def analyze(efile):
    bestmove = '0000'

    p = Popen([efile], stdout=PIPE, stdin=PIPE, stderr=STDOUT, bufsize=0, text=True)  # stderr=STDOUT, also send stderr to stdout to see everything in stdout

    ecommand(p, 'position startpos moves e2e4 e7e5 e1e2')
    ecommand(p, 'go nodes 3000')

    for line in iter(p.stdout.readline, ''):  # read each line of engine output as replies from our command
        line = line.strip()
        print(line)

        if line.startswith('bestmove'):  # exit the loop when we get the engine bestmove
            bestmove = line.split()[1].strip()
            break

    ecommand(p, 'quit')  # properly quit the engine

    # Make sure process 'p' is terminated (if not terminated for some reason) as we already sent the quit command.
    try:
        p.communicate(timeout=5)
    except TimeoutExpired:  # If timeout has expired and process is still not terminated.
        p.kill()
        p.communicate()

    return bestmove


efile = 'E:\\Chess_Engines\\Lc0\\lc0-v0.28.0-windows-cpu-openblas\\lc0.exe'
bestmove = analyze(efile)
print(f'best move: {bestmove}')

Output

_
|   _ | |
|_ |_ |_| v0.28.0 built Aug 25 2021
Detected 4 core(s) and 8 thread(s) in 1 group(s).
...

info depth 1 seldepth 2 time 181 nodes 2 score cp 88 nps 142 tbhits 0 pv g8f6 d2d3
info depth 2 seldepth 3 time 200 nodes 3 score cp 89 nps 90 tbhits 0 pv g8f6 d2d3 d7d5
info depth 2 seldepth 4 time 236 nodes 5 score cp 93 nps 72 tbhits 0 pv g8f6 b1c3 b8c6 d2d3
info depth 3 seldepth 5 time 305 nodes 15 score cp 99 nps 107 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 d5d4
info depth 3 seldepth 6 time 368 nodes 23 score cp 96 nps 114 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 d5d4 c3b1
info depth 4 seldepth 7 time 466 nodes 34 score cp 105 nps 113 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 d5d4 c3b1 b8c6
info depth 4 seldepth 8 time 561 nodes 55 score cp 106 nps 139 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 d5d4 c3b1 b8c6
info depth 5 seldepth 8 time 871 nodes 105 score cp 109 nps 149 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c8e6 g1f3
info depth 5 seldepth 9 time 965 nodes 119 score cp 111 nps 149 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c8e6 g1f3
info depth 5 seldepth 10 time 1327 nodes 179 score cp 109 nps 154 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c8e6 g1f3 d5d4
info depth 5 seldepth 11 time 1444 nodes 206 score cp 110 nps 161 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c8e6 g1f3 d5d4 c3b1
info depth 5 seldepth 12 time 1621 nodes 240 score cp 110 nps 165 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c8e6 g1f3 d5d4 c3b1
info depth 6 seldepth 12 time 2126 nodes 331 score cp 112 nps 168 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c8e6 g1f3 d5d4 c3b1
info depth 6 seldepth 13 time 2582 nodes 430 score cp 111 nps 178 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c8e6 g1f3 d5d4 c3b1
info depth 6 seldepth 14 time 5050 nodes 1037 score cp 111 nps 212 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c8e6 e4d5 c6d4 e2d2 e6d5
info depth 7 seldepth 14 time 5569 nodes 1161 score cp 111 nps 214 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c8e6 e4d5 c6d4 e2d2 e6d5
info depth 7 seldepth 15 time 8385 nodes 1938 score cp 109 nps 235 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c6d4 e2e1 c7c6 g1f3 d8b6 a1b1 c8e6 f3e5
info depth 7 seldepth 15 time 8642 nodes 2007 score cp 109 nps 236 tbhits 0 pv g8f6 d2d3 d7d5 b1c3 b8c6 c1g5 c6d4 e2e1 c7c6 g1f3 d8b6 a1b1 c8e6 f3e5
bestmove g8f6 ponder d2d3
best move: g8f6

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM