C#中如何导出OR-Tools CP-SAT的log_search_progress日志?
作业车间调度问题中CP-SAT求解器日志导出的C#实现方案
问题背景
使用C#开发环境,基于OR-Tools的CP-SAT求解器处理作业车间调度问题,需要将log_search_progress的日志内容导出到TXT文件,但现有尝试未成功。
当前求解代码
// Solve CpSolver solver = new(); List<TaskWithSchedules> tasksToProcess = taskWithSchedules; decimal timePerTask = _settingsCapacityPlan.AllowedSolverTimePerTaskInSeconds; decimal solverLimit = timePerTask * tasksToProcess.Count; // solver needs at least 3 seconds even with the smallest sets int solverLimitInt = Math.Max((int)Math.Round(solverLimit, 1), 3); List<string> solverParameters = new() { string.Format("max_time_in_seconds: {0}.0", solverLimitInt), "log_search_progress:true", // "relative_gap_limit: 0.1" }; solver.StringParameters = string.Join(",", solverParameters); _log.Info($"Solver started"); // model.ExportToFile($"model_file_{solveIteration}.txt"); CpSolverStatus status = solver.Solve(model);
失败的尝试
曾尝试通过以下代码获取日志,但调试时log字符串始终为空:
string log; solver.SetLogCallback((x) => log = x);
Python参考实现
Python中实现该功能较为简单:
solver = cp_model.CpSolver() solver.parameters.log_search_progress = True # Custom log function, for example, using the Python logging module instead of stdout # Useful in a Jupyter notebook, where logging to stdout might not be visible solver.log_callback = print # (str)->None # If using a custom log function, you can disable logging to stdout solver.parameters.log_to_stdout = False
解决方案
C#版OR-Tools完全支持日志回调功能,问题出在日志的累计方式上,修正方案如下:
1. 用StringBuilder累计日志片段
回调函数会逐段输出日志内容,而非一次性返回完整日志,因此不能直接赋值覆盖,需要用StringBuilder追加内容:
// 初始化日志构建器 var logBuilder = new StringBuilder(); // 设置回调,逐段追加日志 solver.SetLogCallback((message) => { logBuilder.AppendLine(message); // 若求解时间长,可直接逐行写入文件避免内存占用过高 // File.AppendAllText("solver_log.txt", message + Environment.NewLine); });
2. 调整求解器参数(可选)
如果不想日志同时输出到控制台,可在参数列表中添加log_to_stdout:false:
List<string> solverParameters = new() { string.Format("max_time_in_seconds: {0}.0", solverLimitInt), "log_search_progress:true", "log_to_stdout:false" // 关闭控制台日志输出 };
3. 求解完成后导出日志
求解结束后,将累计的日志写入TXT文件:
CpSolverStatus status = solver.Solve(model); // 将日志写入文件 File.WriteAllText("solver_log.txt", logBuilder.ToString());
核心原因说明
原代码中log = x会每次覆盖之前的日志内容,而CP-SAT的日志回调是分多次调用的,每次传入一段日志片段,因此必须通过累计的方式收集完整日志。
内容的提问来源于stack exchange,提问作者PeterK
相关产品推荐
相关产品推荐

