使用 io.WriteString 时可执行文件提前退出
executable exits early when using io.WriteString
我正在使用 io 包来处理我的 PATH 中定义的可执行文件。
可执行文件称为“Stockfish”(国际象棋引擎),显然可以通过命令行工具使用。
为了让引擎搜索最佳着法,您使用“go depth n”——深度越高——搜索所需的时间越长。
使用我的命令行工具,它使用 20 的深度搜索了大约 5 秒,它看起来像这样:
go depth 20
info string NNUE evaluation using nn-3475407dc199.nnue enabled
info depth 1 seldepth 1 multipv 1 score cp -161 nodes 26 nps 3714 tbhits 0 time 7 pv e7e6
info depth 2 seldepth 2 multipv 1 score cp -161 nodes 51 nps 6375 tbhits 0 time 8 pv e7e6 f1d3
info depth 3 seldepth 3 multipv 1 score cp -161 nodes 79 nps 7900 tbhits 0 time 10 pv e7e6 f1d3 g8f6
info depth 4 seldepth 4 multipv 1 score cp -161 nodes 113 nps 9416 tbhits 0 time 12 pv e7e6 f1d3 g8f6 b1c3
[...]
bestmove e7e6 ponder h2h4
现在,使用 io.WriteString 它在几毫秒后完成,没有任何(可见的)计算:
(这也是下面代码的输出)
Stockfish 14 by the Stockfish developers (see AUTHORS file)
info string NNUE evaluation using nn-3475407dc199.nnue enabled
bestmove b6b5
这是我使用的代码:
func useStockfish(commands []string) string {
cmd := exec.Command("stockfish")
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
for _, cmd := range commands {
writeString(cmd, stdin)
}
err = stdin.Close()
if err != nil {
log.Fatal(err)
}
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
return string(out)
}
func writeString(cmd string, stdin io.WriteCloser) {
_, err := io.WriteString(stdin, cmd)
if err != nil {
log.Fatal(err)
}
这是我如何使用它的一个例子。第一个命令是设置位置,第二个命令是计算深度为 20 的下一个最佳着法。结果如上所示。
func FetchComputerMove(game *internal.Game) {
useStockfish([]string{"position exmaplepos\n", "go depth 20"})
}
要利用像 stockfish
这样的引擎 - 您需要启动该过程并 保持 它 运行ning.
您正在执行它,通过 Stdin 管道传递 2 个命令,然后关闭管道。关闭管道向程序表明您不再对引擎必须说的内容感兴趣。
到 运行 它 - 并保留它 运行ning - 你需要这样的东西:
func startEngine(enginePath string) (stdin io.WriteCloser, stdout io.ReadCloser, err error) {
cmd := exec.Command(enginePath )
stdin, err = cmd.StdinPipe()
if err != nil {
return
}
stdout, err = cmd.StdoutPipe()
if err != nil {
return
}
err = cmd.Start() // start command - but don't wait for it to complete
return
}
返回的管道允许您发送命令并实时查看输出:
stdin, stdout, err := startEngine("/usr/local/bin/stockfish")
sendCmd := func(cmd string) error {
_, err := stdin.Write([]byte(cmd + "\n"))
return err
}
sendCmd("position examplepos")
sendCmd("go depth 20")
然后粗略地读取异步响应:
b := make([]byte, 10240)
for {
n, err := stdout.Read(b)
if err != nil {
log.Fatalf("read error: %v", err)
}
log.Println(string(b[:n]))
}
一旦出现bestmove d2d4 ponder g8f6
这样的行,就知道当前的分析命令已经完成。
然后您可以关闭引擎(通过关闭 stdin
管道)(如果您只需要),或者保持打开状态以供进一步提交命令。
我正在使用 io 包来处理我的 PATH 中定义的可执行文件。 可执行文件称为“Stockfish”(国际象棋引擎),显然可以通过命令行工具使用。
为了让引擎搜索最佳着法,您使用“go depth n”——深度越高——搜索所需的时间越长。 使用我的命令行工具,它使用 20 的深度搜索了大约 5 秒,它看起来像这样:
go depth 20
info string NNUE evaluation using nn-3475407dc199.nnue enabled
info depth 1 seldepth 1 multipv 1 score cp -161 nodes 26 nps 3714 tbhits 0 time 7 pv e7e6
info depth 2 seldepth 2 multipv 1 score cp -161 nodes 51 nps 6375 tbhits 0 time 8 pv e7e6 f1d3
info depth 3 seldepth 3 multipv 1 score cp -161 nodes 79 nps 7900 tbhits 0 time 10 pv e7e6 f1d3 g8f6
info depth 4 seldepth 4 multipv 1 score cp -161 nodes 113 nps 9416 tbhits 0 time 12 pv e7e6 f1d3 g8f6 b1c3
[...]
bestmove e7e6 ponder h2h4
现在,使用 io.WriteString 它在几毫秒后完成,没有任何(可见的)计算: (这也是下面代码的输出)
Stockfish 14 by the Stockfish developers (see AUTHORS file)
info string NNUE evaluation using nn-3475407dc199.nnue enabled
bestmove b6b5
这是我使用的代码:
func useStockfish(commands []string) string {
cmd := exec.Command("stockfish")
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
for _, cmd := range commands {
writeString(cmd, stdin)
}
err = stdin.Close()
if err != nil {
log.Fatal(err)
}
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
return string(out)
}
func writeString(cmd string, stdin io.WriteCloser) {
_, err := io.WriteString(stdin, cmd)
if err != nil {
log.Fatal(err)
}
这是我如何使用它的一个例子。第一个命令是设置位置,第二个命令是计算深度为 20 的下一个最佳着法。结果如上所示。
func FetchComputerMove(game *internal.Game) {
useStockfish([]string{"position exmaplepos\n", "go depth 20"})
}
要利用像 stockfish
这样的引擎 - 您需要启动该过程并 保持 它 运行ning.
您正在执行它,通过 Stdin 管道传递 2 个命令,然后关闭管道。关闭管道向程序表明您不再对引擎必须说的内容感兴趣。
到 运行 它 - 并保留它 运行ning - 你需要这样的东西:
func startEngine(enginePath string) (stdin io.WriteCloser, stdout io.ReadCloser, err error) {
cmd := exec.Command(enginePath )
stdin, err = cmd.StdinPipe()
if err != nil {
return
}
stdout, err = cmd.StdoutPipe()
if err != nil {
return
}
err = cmd.Start() // start command - but don't wait for it to complete
return
}
返回的管道允许您发送命令并实时查看输出:
stdin, stdout, err := startEngine("/usr/local/bin/stockfish")
sendCmd := func(cmd string) error {
_, err := stdin.Write([]byte(cmd + "\n"))
return err
}
sendCmd("position examplepos")
sendCmd("go depth 20")
然后粗略地读取异步响应:
b := make([]byte, 10240)
for {
n, err := stdout.Read(b)
if err != nil {
log.Fatalf("read error: %v", err)
}
log.Println(string(b[:n]))
}
一旦出现bestmove d2d4 ponder g8f6
这样的行,就知道当前的分析命令已经完成。
然后您可以关闭引擎(通过关闭 stdin
管道)(如果您只需要),或者保持打开状态以供进一步提交命令。