Owned stdout lock

Right now, in order to get a locked stdout, one needs to do as such:

let stdout = std::io::stdout();
let stdout = stdout.lock();

In order to get optimal performance, it's actually this:

let stdout = std::io::stdout();
let stdout = std::io::BufWriter::new(stdout.lock());

It'd be nice if there were a shorthand for this. Perhaps one could be an owned lock, perhaps: fn Stdout::into_locked(self) (or just locked(self)).

The BufWriter thing is less concerning, but it seems to be a best kept secret of squeezing performance out of stdout.

Stdout and StdoutLock already write to a LineWriter, which is a newline-flushing BufWriter. Are you adding another BufWriter layer just to batch that even further?

@cuviper, yes, I have some programs that produce a huge amount of data on stdout and I rather avoid having a syscall for each and every line.

Nevertheless, I actually wrote this to bring attention to how I dislike how locking the stream is so wordy.

Tbh, the best performance way to print to stdout is to build up a String and then print it all at once, which can be done without touching a stdout lock or bufwriter (though is theoretically isomorphic to an infinitely buffered bufwriter).

That said, I would not be against an owned variant of StdoutLock and ways of tweaking stdout's internal buffering, so long as it doesn't hurt the common case (println!) performance.

There's an open issue about using block buffering when appropriate:

That said, I agree that having an owning lock would be nice, I have a couple of small CLIs that start with

let input = stdin();
let mut input = input.lock();

let output = stdout();
let mut output = output.lock();

being able to simplify that to one line would be amazing

let (mut input, mut output) = (stdin().locked(), stdout().locked());

(plus probably another line to switch stdout to block-buffering)

I ran into another reason to have an into_locked()-like function:

Today I tried to do this:

  let stdout = std::io::stdout();
  let verbose: Box<dyn Write+Send>;
  if is_verbose
    { verbose = Box::new(stdout.lock()) as _;  }
  else
    { verbose = Box::new(std::io::sink()) as _; }

  let verbose = Mutex::new(verbose);
   // ... spawn thread

This isn't allowed because the locked stdout needs to have a non-Send reference to the unlocked stdout. So I need to just lock the locked stdout with the Mutex, which is too many locks!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.