I would like to ask for comments and suggestions on my solution to the following problem. I maintain a frontend to gnuplot, which implements the following plotting process:
- Run gnuplot and connect to it via stdin, stdout, and stderr
- Send plotting commands to gnuplot by writing to its stdin (gnuplot may take an arbitrary amount of time to run these commands)
- Ask gnuplot to print sigil strings to its stdout and stderr
- Read gnuplot’s stdout and stderr
- Go to step 2.
Julia’s documentation and suggested solutions to inter-process communications focus on a scenario where a process starts, returns something, and finishes, which is different than the case described above.
Essentially, the problem I need to solve is to
read() the data available in gnuplot’s stdout and stderr while the pipes are still open and gnuplot is still running. Until now, I’ve been relying on
readavailable(), but that approach is no longer recommended. The difficulties I’m facing are the following:
read(p::Pipe)blocks until the pipe is closed.
read(p, nb, all=false)is not supported when
- I could
readuntilthe sigil string is read, but
readuntil(p::Pipe, s)is likewise not supported.
I have come up with a solution based on
bytesavailable(), included below. I have one function to start gnuplot, another to end it, and a main function
communicate() to perform steps 2–4 above. This code is not super polished yet, but it works in my experiments so far. I’d like to ask for comments and suggestions. Thanks in advance!
"Step 1: Start gnuplot process." function startgp() inp = Pipe() out = Pipe() err = Pipe() process = run(pipeline(`gnuplot`, stdin=inp, stdout=out, stderr=err), wait=false) close(out.in) close(err.in) # Communication fails without these Base.start_reading(out.out) Base.start_reading(err.out) return (process, inp, out, err) end "End gnuplot process `p`" function endgp(p) write(p, "exit gnuplot\n") close(p) wait(p) return p.exitcode end "Send `input` to process `p` and return its response." function communicate(p, input) inp = p out = p err = p gpout = @async begin while true b = bytesavailable(out) if b == 0 sleep(0.01) continue else return String(read(out, b)) end end end gperr = @async begin while true b = bytesavailable(err) if b == 0 sleep(0.01) continue else return String(read(err, b)) end end end # Step 2: send user input to gnuplot write(inp, input) # Step 3: ask gnuplot to return sigils when it is done write(inp, """\nset print '-' print 'Done' set print print 'Done'\n""") # Step 4: read gnuplot's stdout and stderr return ( fetch(gpout), fetch(gperr) ) end