python-chess调用Stockfish分析时意外终止问题求助
批量FEN评估崩溃问题的诊断与解决
问题概述
使用python-chess调用Stockfish对100万个FEN局面进行评估打分,处理到第25430个局面时程序意外终止,报错显示引擎进程因栈溢出崩溃。更换不同引擎后仍在同一位置失败,手动解析大JSON文件未使用JSON库,但排除解析代码导致问题的可能。
复现代码
import chess import chess.engine def stockfish_evaluation(board): result = engine.analyse(board, chess.engine.Limit(depth=1)) return result['score'].relative.score(mate_score=10000) engine = chess.engine.SimpleEngine.popen_uci("/usr/bin/stockfish") inputf = "lichess-1M.json" outputf = open("out-1M.data","w") line_num = sum(1 for _ in open(inputf)) line_count = 0 file = open(inputf) while True: data = '' line_buf = 0 # 按25000行分块读取JSON文件(单行为一个局面,受内存限制) for line in file: line_count += 1 line_buf += 1 print('\r'+f"Processing - {line_count}/{line_num} ({format(line_count/line_num*100,'.2f')}%) ",end='') data += line + '\n' if line_buf >= 25000: break # 手动提取FEN字段 n = 0 s = '' isFen = False while n < len(data): if isFen: s += data[n] if data[n] == '"': isFen = False # 调用评估函数并写入结果 outputf.write(f"{s}: {stockfish_evaluation(chess.Board(s[1:-1]))}\n") elif data[n:n+6] == '"fen":': isFen = True n += 6 s = '"' n += 1
报错信息
<UciProtocol (pid=1014814)>: stderr >> *** stack smashing detected ***: terminated Traceback (most recent call last): File "/home/user/Downloads/chess/test.py", line 33, in <module> outputf.write(f"{s}: {stockfish_evaluation(chess.Board(s[1:-1]))}\n") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/user/Downloads/chess/test.py", line 5, in stockfish_evaluation result = engine.analyse(board, chess.engine.Limit(depth=1)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/user/.local/lib/python3.11/site-packages/chess/engine.py", line 2996, in analyse return future.result() ^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/concurrent/futures/_base.py", line 456, in result return self.__get_result() ^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result raise self._exception File "/usr/lib/python3.11/asyncio/tasks.py", line 452, in wait_for return await fut ^^^^^^^^^ File "/home/user/.local/lib/python3.11/site-packages/chess/engine.py", line 1242, in analyse await analysis.wait() File "/home/user/.local/lib/python3.11/site-packages/chess/engine.py", line 2771, in wait return await self._finished ^^^^^^^^^^^^^^^^^^^^ chess.engine.EngineTerminatedError: engine process died unexpectedly (exit code: -6)
输出文件检查结果
$ cat out-1M.data | wc -l 25340
解决步骤
1. 定位触发崩溃的FEN
程序在固定位置崩溃,大概率是该位置的FEN存在异常:
- 修改代码,在处理到第25430行时单独输出对应的FEN字符串。
- 用
chess.Board(fen_str)验证FEN合法性,再手动调用Stockfish评估该FEN,确认是否触发崩溃。
2. 提升程序鲁棒性,避免引擎崩溃终止整体任务
添加异常捕获与引擎重启逻辑,确保单个FEN的问题不中断整个任务:
def stockfish_evaluation(board): try: result = engine.analyse(board, chess.engine.Limit(depth=1)) return result['score'].relative.score(mate_score=10000) except chess.engine.EngineTerminatedError: # 重启引擎 global engine engine.quit() engine = chess.engine.SimpleEngine.popen_uci("/usr/bin/stockfish") # 重试一次 try: result = engine.analyse(board, chess.engine.Limit(depth=1)) return result['score'].relative.score(mate_score=10000) except Exception as e: print(f"Failed evaluating FEN: {board.fen()}, error: {str(e)}") return None except Exception as e: print(f"Error evaluating FEN: {board.fen()}, error: {str(e)}") return None
3. 替换手动JSON解析,避免解析错误
手动解析大JSON容易出现边界问题(比如FEN含转义字符),改用流式JSON库ijson,既节省内存又保证解析准确性:
import ijson # 替换原文件读取与解析逻辑 with open(inputf, 'r') as f: for line_count, item in enumerate(ijson.items(f, 'item'), 1): fen = item.get('fen') if not fen: continue score = stockfish_evaluation(chess.Board(fen)) if score is not None: outputf.write(f'"{fen}": {score}\n') print('\r'+f"Processing - {line_count}/{line_num} ({format(line_count/line_num*100,'.2f')}%) ",end='')
安装ijson:pip install ijson
4. 引擎参数优化与版本升级
- 升级Stockfish到最新稳定版,旧版本可能存在特定FEN的处理bug。
- 限制引擎哈希表大小,降低内存与栈压力:
engine = chess.engine.SimpleEngine.popen_uci("/usr/bin/stockfish") engine.configure({"Hash": 64}) # 设置为64MB,可根据内存情况调整
内容的提问来源于stack exchange,提问作者Darwish
相关产品推荐
相关产品推荐

