【问题标题】:File Exception Handling and wait for a process in SWI Prolog文件异常处理并等待 SWI Prolog 中的进程
【发布时间】:2025-12-26 14:50:12
【问题描述】:

我在 SWI Prolog 和 Windows 7 上运行我的代码。在我的代码中,我使用 'win_exec()' 调用另一个应用程序(我尝试使用方法 'shell()',但它不起作用。),最后在文本文件中生成其输出。但是有时它会运行 30 分钟。现在我的序言代码使用这个输出文本文件,进一步解析和处理它。 这是我用来调用其他应用程序然后使用其输出文件的代码:

main(Value,X) :- win_exec('C:\\myfolder\\external_app.bat C:\\myfolder\\outputfile.txt', normal),
                 open('C:\\myfolder\\outputfile.txt', read, Mf),
                 read_file(Mf, X),  % PROCEDURE TO READ FILE CONTENTS 
                 close(Mf),
                 statistics(cputime, Value). % CALCULATE HOW LONG IT TOOK

但是,由于该文件尚未由另一个应用程序输出,因此会出现错误:

ERROR: open/4: source_sink `C:\myfolder\outputfile.txt' does not exist (No such file or directory)

因此,作为一种解决方法,我尝试捕获错误,通过与“existence_error”进行比较来处理它,然后递归调用 open 过程,直到它最终成功,即其他应用程序已完成其处理并生成输出文件.这是我的解决方法代码:

main(Value,X) :- win_exec('C:\\myfolder\\external_app.bat C:\\myfolder\\outputfile.txt', normal),
                 open_output(X),   % PROCEDURE FOR FILE EXCEPTION HANDLING
                 statistics(cputime,Value).

open_output(X) :- catch((open('C:\\myfolder\\outputfile.txt', read, Mf), read_file(Mf,X), close(Mf)),
                         error(Err,Context),
                         open_output_aux(Err,X)). % AUX PROCEDURE TO RECOVER

% Write some code here
% open_output_aux code matches the error code with 'existence_error';
% if true, calls open_aux_wait procedure; else throw the error.

open_aux_wait(Z):- catch((open('C:\\myfolder\\outputfile.txt', read, Mf), read_file(Mf,Z), close(Mf)),
                   error(Err,Context),
                   open_aux_wait(Z)).

但是,这样做似乎效率很低。我想知道是否有更好的方法来做到这一点,比如在 java 中,你可以在处理文件异常时简单地调用 wait() 。在文档中,有一个方法“wait_for_input\3”,但它说“wait_for_input()”不能用于 Windows 中的文件流。我尝试使用它,但它给出了错误。

非常感谢任何帮助或指导。

【问题讨论】:

    标签: windows-7 prolog wait swi-prolog nosuchfileexception


    【解决方案1】:

    您有多种选择来解决这个问题:

    1. 您完全可以重新考虑这些进程的通信方式。例如,SWI-Prolog 带有非常强大的 HTTP 库,您可以使用客户端/服务器架构设置两个进程之间的通信以通过 HTTP 工作。在这种情况下,您可以避免当前不必要地使用许多 CPU 周期的忙等待

    2. 更简单的解决方案是在尝试再次打开文件之前简单地插入对内置 sleep/1 谓词的调用以使进程进入睡眠状态。例如,使用 sleep(1) 使进程休眠 1 秒。

    3. 例如使用process_wait/2 等待被调用的进程完成并生成文件。

    根据您的描述,看起来 (2) 可以,(3) 稍微优雅一些​​,并且 (1) 对于更困难的情况,一般来说可能很好了解。

    【讨论】:

    • 感谢您的建议。它们都很好,但是我最初不想使用 sleep/1,因为它弄乱了我的统计信息/2,因为我想计算整个过程花费的时间。此外,另一个应用程序有时会在几秒钟内输出,而有时甚至需要几个小时。所以我担心我的代码是否会崩溃。我了解一些技术,比如只是轮询一下,或者中断不能在这里工作。
    • 我添加了方法(3),希望更适合你的场景:使用process_wait/2等待被调用进程完成,然后读取文件。您可能需要稍微更改调用流程的方式来执行此操作。另请注意,您可以使用例如 sleep(0.1),显着降低 CPU 负载并保持更可接受的性能。
    • 但我在考虑类似 1)我的代码调用另一个 win_shell/3 或 win_exec/2(并行任务),它运行一些脚本来检查输出文件的存在并返回状态码。或者,2)我没有调用 win_exec 直接调用其他应用程序,而是使用 win_exec 调用 'cmd.exe /K external_app.bat' 并让 cmd 通知我输出文件存在的状态。我不知道有任何这样的 cmd 开关可以完成这项工作。希望代码不会因为过多的 cpu 周期而崩溃,不应该有堆栈溢出,因为 open_aux_wait 应该是尾递归的。
    • 为了更好的可移植性和简化所涉及进程的交互,我建议您只需使用process_create/3 启动外部进程,使用process(PID) 选项,然后使用process_wait/2 等待PID 直到完成。这很简单,也可以移植到其他平台。
    • 你应该把它变成一个自己的问题。乍一看,我可以想象您需要指定[stdin(pipe(Stream))] 作为第三个参数,以便您可以将进一步的输入传递给进程。