next_line yields Ready(None) instead of Pending causing tight polling issues when using it on a select! loop #7401
-
I encountered this behavior when implementing a logic to polls two different BuffReaders reading from files actively being written on by a different process. The following select loop was consuming way more cpu than I had expected and strace shows excessive tokio::select! {
f1_result = f1.next_line() => {
...
}
f2_result = f2.next_line() => {
...
}
} Reading poll_next_line's implementation, I see it yields pub fn poll_next_line(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<io::Result<Option<String>>> {
let me = self.project();
let n = ready!(read_line_internal(me.reader, cx, me.buf, me.bytes, me.read))?;
debug_assert_eq!(*me.read, 0);
if n == 0 && me.buf.is_empty() {
return Poll::Ready(Ok(None));
}
if me.buf.ends_with('\n') {
me.buf.pop();
if me.buf.ends_with('\r') {
me.buf.pop();
}
}
Poll::Ready(Ok(Some(mem::take(me.buf))))
} I haven't read the internals of |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Tokio returns |
Beta Was this translation helpful? Give feedback.
Tokio returns
Ready(None)
if the file is empty. Transferring data by actively appending to the file from another process isn't very well supported - Tokio assumes that when the file is empty, it stays empty. I suggest you use a pipe instead to transfer data between processes, as pipes are not considered empty when you reach the end.