I want to make a CLI program that listens to stdin...
# getting-started
y
I want to make a CLI program that listens to stdin until end of input, outputs something to stdout based on the input, then goes back to listening. but I want to make it so that the program doesn't sit there spin-looping while there's no input. how can I do this?
l
If it's listening / waiting for the input, the user must know it. A cursor blinking in the terminal, an ASCII doing backflips, whatever, but user must know. Otherwise he/she doesn't know the CLI program is running, therefore maybe never writing the input.
CLI program waiting the user ♾️ the user who doesn't know the program is waiting for him/her
y
in reality, it's not using the terminal at all. I've got another program that is running and occasionally needs to send input to a kotlin program, and get the output.
currently I'm spawning a new process to do this (kotlin program starts listening on stdin until EOF, outputs on stdout, exits)
c
Reading from STDIN in blocking, you can just read and the system will handle waking up the program when input arrives
(well, all files, not just STDIN)
*on the JVM
y
wait, really?
c
Yeah, that's why
|
in bash works, the system handles waking up all processes in the chain whenever they receive data / putting to sleep the processes at the start if the next ones can't match the speed
y
I see! great. then would something like this
Copy code
while (true) {
    val input = generateSequence(::readLine)
    if (input.isNotEmpty()) { 
        process(input) 
    }
}
just block in the
val input
line until input starts, read until input ends, then just go back to blocking on the beginning of the next iteration of the
while
?
assuming the other side waits for output before sending.
c
Yes, each
readLine
call which doesn't have enough characters to read a full line, is blocked by the OS
y
huh. thanks a lot. talk about an XY problem.
c
Turns out it's something so many programs need, that it's just how it works already 😅
❤️ 1
But yeah, "blocking I/O" == "the OS has put me to sleep because not enough data is available, and will wake me up whenever more data arrives"
👀 1
whereas "asynchronous I/O" == "there is not enough data so I'm doing something else, and the OS will tell me whenever more data arrives so I can go back to processing it"
^ both of these happen at the level of the thread, so one thread being blocked waiting for I/O doesn't mean anything for the other threads (they can continue doing their thing)
y
so blocking is sometimes "bad" because maybe you don't want to be constantly listening and if I were to use a non-blocking option, my thread has the ability to also do other stuff while potentially having a delay before it handles the input?
c
In both blocking and asynchronous I/O, when properly implemented (and you can assume the standard library implements it correctly), the waiting is done by the OS, not the program.
Blocking I/O is usually simpler for small programs (it's a really easy mental model: call the function, it returns when data is available), but it's hard to implement timeouts and stuff (your thread stops executing, it can't do anything else). Since the thread cannot do anything else, some platforms forbid you to block the UI thread to avoid blocking the UI (e.g. Android, JS). Asynchronous I/O is interesting the more blocking stuff you do at the same time. For example, for a web server that has to read from 1000 files at the same time, blocking I/O costs 1000 threads, whereas asynchronous I/O lets these threads do something else. That's why the Kotlin team created Coroutines : they allow to write code with a mental model really similar to blocking code ("it returns when data is available"), but it uses asynchronous operations under the hood. That's also the goals of virtual threads on the JVM (though they are optimized for different needs)
👀 1
But yeah, for a CLI app, you probably don't have anything else to do, so I'd stick with blocking I/O for their simplicity. Threads are a bit expensive, so whenever you start to need 20+ threads you should consider asynchronous instead.
1 000+ threads on a typical consumer machine will probably hog all resources, whereas 1 000 000+ coroutines is fine
Also, all (modern) frameworks for web development do everything asynchronously (Spring, Netty, Ktor…) even if you don't see it happening
y
thanks a lot. a lot of good info.