julia

bytesavailable(stdin) always returns 0


I have a Julia function that needs to readline(stdin) in a non-blocking way. When I try to use the bytesavailable(stdin) function, it always returns 0, even when there are data ready to read. If anyone has some insight into this, I would greatly appreciate your suggestions.

Below is an example. I am using Julia version 1.11.3.

# Test bytesavailable(stdin)

# Create a pipe
(rd, wr) = redirect_stdin()

# Write to the write end of the pipe
write(wr, "test 1\n")
write(wr, "test 2\n")
flush(wr) # Make sure the data is written

bytesavailable(stdin) # returns 0
bytesavailable(rd)    # returns 0
eof(rd)               # returns false
readline(stdin)       # "test 1"
readline(rd)          # "test 2"

# Close the pipe
close(rd)
close(wr)

Solution

  • The method bytesavailable is, at best, a hint that readavailable uses internally. The documentation on bytesavailable is sparse, but the documentation for readavailable says:

    Read available buffered data from a stream. Actual I/O is performed only if no data has already been buffered...

    There is an additional warning:

    The amount of data returned is implementation-dependent; for example it can depend on the internal choice of buffer size. Other functions such as read should generally be used instead.

    The key is the "buffered data" bit. The stdin constant is not implemented in Julia as a buffered stream of any kind: in fact, it isn't implemented in Julia at all, and is instead implemented using the libuv C library to abstract away the OS-specific stuff. It is likely that whoever implemented terminal stream communication in Julia did not want to try to figure out the internals of every possible OS's implementation of standard input to determine if it is buffered and what that buffer size is, so bytesavailable returning 0 just tells you that any read from stdin might reach out to the OS.

    bytesavailable should probably not be used as an indication of whether the IO object is ready to read anything. If you want to read from stdin in a way that is guaranteed to be non-blocking, consider spawning a separate Task with @async that reads and pushes the data into a Channel.