dhmitchell

dhmitchell

Kotlin Coroutine Confidence: asynchronous read file

In “gallery/v14/src/main/kotlin/com/example/gallery/GetImageFromFile.kt”

  • won’t the .use always call channel.close() on exit? if so, why do you need invokeOnCancellation? or does cancellation somehow avoid the finally in the use?
  • if I wanted to iterate through the file line by line, I presume I’d call readline rather than read and otherwise it’s roughly the same?

Marked As Solved

sam-cooper

sam-cooper

Author of Kotlin Coroutine Confidence

Yes, since the use() block wraps the entire call to suspendCancellableCoroutine(), it will always close the AsynchronousFileChannel when suspendCancellableCoroutine() exits for any reason. The problem is that without that invokeOnCancellation() block, suspendCancellableCoroutine() will not exit—at least, not until we’ve finished reading the entire file.

What we’re trying to do by adding invokeOnCancellation() is to ensure that we can stop the file operation before it finishes. When the coroutine is cancelled, Kotlin executes the invokeOnCancellation() block. Calling channel.close() inside the block is how we interrupt the ongoing file operation and cause it to end early.

That means there are two different ways the file can be closed:

  1. The read() operation ends on its own, either because it reached the end of the file or because it ran into an I/O error. The suspension point resumes, and the coroutine exits the use() block, closing the channel in the process.
  2. The user cancels the coroutine before read() is done. This triggers invokeOnCancellation(), which in turn calls channel.close(). This fires the read() operation’s failed() callback, allowing the coroutine to resume from its suspended state without waiting for the rest of the data. Again, it exits the use() block, but the file channel is already closed, so that’s a no-op.

I’ll see what I can do to make all this clearer in the book! Although it’s not something you’re likely to have to deal with often, I’d like to make sure it’s clear.

As for the second question, that’s a little trickier. The AsynchronousFileChannel just deals with raw byte data, and it doesn’t have any methods for working with text or line separators. Unfortunately that means there’s no readLine() function. You could write one of your own, but you’d need to include logic to buffer the data in chunks, inspect it for line separators, and so on.

In a real application, it’s likely that the more complete feature set of the java.io libraries will outweigh any asynchronous advantage from using java.nio. If I needed to read lines from a text file, I’d probably just use a good old fashioned Reader, and accept the minor cost of a blocked IO thread. In the book, I’m not intending to advocate for using AsynchronousFileChannel all over the place—it’s just meant as a handy example of a simple (ish) operation that we can use to illustrate asynchronous callbacks. Perhaps I’ll add a quick note to that effect in the text, too.

Phew! With any luck, I’ll find a way to say all this in the book using slightly fewer words. Thanks for asking these questions—they all help me to make the explanations in the book clearer.

Where Next?

Popular Pragmatic Bookshelf topics Top

jamis
The following is cross-posted from the original Ray Tracer Challenge forum, from a post by garfieldnate. I’m cross-posting it so that the...
New
edruder
I thought that there might be interest in using the book with Rails 6.1 and Ruby 2.7.2. I’ll note what I needed to do differently here. ...
New
lirux
Hi Jamis, I think there’s an issue with a test on chapter 6. I own the ebook, version P1.0 Feb. 2019. This test doesn’t pass for me: ...
New
cro
I am working on the “Your Turn” for chapter one and building out the restart button talked about on page 27. It recommends looking into ...
New
adamwoolhether
When trying to generate the protobuf .go file, I receive this error: Unknown flag: --go_opt libprotoc 3.12.3 MacOS 11.3.1 Googling ...
New
curtosis
Running mix deps.get in the sensor_hub directory fails with the following error: ** (Mix) No SSH public keys found in ~/.ssh. An ssh aut...
New
jonmac
The allprojects block listed on page 245 produces the following error when syncing gradle: “org.gradle.api.GradleScriptException: A prob...
New
andreheijstek
After running /bin/setup, the first error was: The foreman' command exists in these Ruby versions: That was easy to fix: gem install fore...
New
redconfetti
Docker-Machine became part of the Docker Toolbox, which was deprecated in 2020, long after Docker Desktop supported Docker Engine nativel...
New
New

Other popular topics Top

PragmaticBookshelf
Write Elixir tests that you can be proud of. Dive into Elixir’s test philosophy and gain mastery over the terminology and concepts that u...
New
PragmaticBookshelf
Use WebRTC to build web applications that stream media and data in real time directly from one user to another, all in the browser. ...
New
New
PragmaticBookshelf
Author Spotlight Jamis Buck @jamis This month, we have the pleasure of spotlighting author Jamis Buck, who has written Mazes for Prog...
New
PragmaticBookshelf
Author Spotlight Mike Riley @mriley This month, we turn the spotlight on Mike Riley, author of Portable Python Projects. Mike’s book ...
New
First poster: AstonJ
Jan | Rethink the Computer. Jan turns your computer into an AI machine by running LLMs locally on your computer. It’s a privacy-focus, l...
New
CommunityNews
A Brief Review of the Minisforum V3 AMD Tablet. Update: I have created an awesome-minisforum-v3 GitHub repository to list information fo...
New
PragmaticBookshelf
Explore the power of Ash Framework by modeling and building the domain for a real-world web application. Rebecca Le @sevenseacat and ...
New
AstonJ
This is cool! DEEPSEEK-V3 ON M4 MAC: BLAZING FAST INFERENCE ON APPLE SILICON We just witnessed something incredible: the largest open-s...
New
RobertRichards
Hair Salon Games for Girls Fun Girls Hair Saloon game is mainly developed for kids. This game allows users to select virtual avatars to ...
New

Sub Categories: