因此,我试图使用OCaml与Python进程进行通信。我想将Python程序通过管道传递到Python解释器的stdin,然后在OCaml进程中读回Python程序的输出。
我能够这样解决:
let py_program = {|
import time
while True:
print('hi from Python', flush=True)
time.sleep(0.25)
|}
let exec_py_program () =
let cmd = "", [|"python3"; "-"|] in
let pipe_out_fd, pipe_out_fd_unix = Lwt_unix.pipe_out () in
(* Close the 1st time *)
let () = Lwt_unix.set_close_on_exec pipe_out_fd_unix in
let redir = `FD_move pipe_out_fd in
let py_stream = Lwt_process.pread_lines ~stdin:redir cmd in
let%lwt n = Lwt_unix.write_string pipe_out_fd_unix py_program 0 (String.length py_program) in
if n < String.length py_program then failwith "Failed to write python to pipe" else
let rec read_back () =
match%lwt Lwt_stream.get py_stream with
| Some str ->
let%lwt () = Lwt_io.printl @@ "Got: " ^ str in
read_back ()
| None -> Lwt.return ()
in
(* Close the 2nd time *)
let%lwt () = Lwt_unix.close pipe_out_fd_unix in
read_back ()
我使用“ set_close_on_exec”关闭与注释“ Close the first time”附近映射到Python进程的stdin的管道相对应的文件描述符,并在再次发送Python程序后再次关闭管道(“ Close the 2nd时间”)。 “ set_close_on_exec”应该“在该进程在另一个进程上调用exec时”关闭文件描述符。
如果我不选择其中任何一行,Python进程将无限期地从其stdin中读取数据,并且永远不会开始执行,因此永远不会收到“ hi from Python”。所以我的问题是,为什么这两个都是必要的?这主要是我的猜测。
答案 0 :(得分:2)
在POSIX操作系统(如Linux)上启动程序分两个步骤。首先,将启动程序的进程进行分叉,这将创建正在运行的进程的副本。然后,使用对exec
的调用将新进程替换为新程序。对进程进行分叉时,两个结果进程都会继承所有打开的文件描述符。因此,要实际上关闭文件描述符,必须在两个进程中都将其关闭。
设置close-on-exec标志将导致进程在调用exec
后立即关闭相应的文件描述符。因此,当您设置此标志时,在程序启动后,只有旧进程才具有打开的文件描述符。
另请参阅this question。