Search code examples
d

Control an interactive process using D


I have a program that waits for a line of standard input, and then, after processing it (which takes a relatively long time), emits an answer. The program will take input until the input stream closes.

How could I control that program from D? In other words how could I

  1. Give the child process a line of standard input.
  2. Wait for the child process to answer.
  3. Repeat, until I have exhausted the inputs I want to give to it.

I tried the following code, but not surprisingly, it waits for the child process to finish entirely, and then prints the output all at once:

module main;

import std.file;
import std.path;
import std.process;
import std.stdio;

void main(string[] args)
{
    string[] inputs = ["test string 1", "test string 2"];

    auto pipes = pipeProcess(buildPath(getcwd(), "LittleTextProcessingApp"), Redirect.all);
    scope(exit) wait(pipes.pid);

    foreach(input; inputs)
    {
        pipes.stdin.writeln(input);
    }
    pipes.stdin.close;

    foreach(line; pipes.stdout.byLine)
    {
        writeln(line);
    }
}

That is, it prints, after a one-second delay,

The following was input 500 ms ago: test string 1
The following was input 500 ms ago: test string 2

The desired behavior is that it print

The following was input 500 ms ago: test string 1

after a half second, and the second line 500 ms later.

The source code for the program I am testing as the child process is as follows:

module main;

import std.stdio;
import core.thread;

void main(string[] args)
{
    foreach(input; stdin.byLine)
    {
        auto duration = 500.msecs;
        stderr.writefln("Doing something for %s....", duration);
        Thread.sleep(duration);
        writefln("The following was input %s ago: %s", duration, input);
    }
}

Solution

  • The culprit is the child process. After writefln, the output is not flushed by default. Instead, it is kept in a buffer (a few kilobytes long). This is common technique (not specific to D) which can greatly improve speed when, for example, writing a large file to HDD in lots of few-byte chunks.

    To flush the buffer, use stdout.flush() every time you want the output to appear immediately. Adding that line after the last writefln in your child example's code fixes the situation in the example.