https://kotlinlang.org logo
#coroutines
Title
# coroutines
p

Pacane

08/10/2020, 6:42 PM
Is it a normal behaviour that if I do
Copy code
// This is in a loop
val e = async {
  writeFileToDisk()
}
filesBeingWritten.add(e)

//somewhere else 
filesBeingWritten.awaitAll()
Is much slower than this
Copy code
// This is in a loop
writeFileToDisk()
where
writeFileToDisk()
is a suspending function calling
Copy code
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
  val get = Paths.get(imageFilename)
  Files.write(get, bytes)
}
And by "slower" I mean it never seems to even complete..? Is there a limitation / maximum amount of Deferred objects we can await at a same time?
o

octylFractal

08/10/2020, 6:46 PM
I don't think there's a maximum, but depending how you're calling
async
and where the
awaitAll()
is, you might be causing some unexpected issues
if you can show a full (but minimal) example, it should be explainable
p

Pacane

08/10/2020, 6:48 PM
Copy code
private suspend fun closeMotion(motionDirectory: Path) = coroutineScope {
    // Some code omitted

    val begin = Instant.now()
    val f1 = listOf(*filesBeingWritten.toTypedArray())
    println("Awaiting ${f1.count()} frames to be written.")
    filesBeingWritten.clear()
    try {

      f1.awaitAll()
    } catch (e: Exception) {
      println("AAAA $e")
    }
    println("It took : ${Duration.between(begin, Instant.now()).seconds}")
  }
sure, so here's the part of the code that's calling
awaitAll()
including some time benchmarks
the
filesBeingWritten
object is just a mutableList of
Deferred<Unit>
o

octylFractal

08/10/2020, 6:50 PM
FYI that list copy can be written as
filesBeingWritten.toList()
-- but probably not the issue here
p

Pacane

08/10/2020, 6:50 PM
maybe the stdout is bugged too... because I do print some stuff in
writeFileToDisk
and it only gets printed to stdout once I cancel the root job
does
awaitAll
have a timeout mechanism by default?
d

Dominaezzz

08/10/2020, 7:03 PM
No
c

Casey Brooks

08/10/2020, 7:25 PM
What’s the Disptacher being used when you call
closeMotion
? If it’s a single-threaded dispatcher, then it could be having a deadlock where it spawns an async task, but needs the current task to finish before it can start processing it, but it can’t finish until the new async task has finished
p

Pacane

08/10/2020, 7:26 PM
I assume it's using the Default, but I am doing something different for this one
so this might be the thing
here's what I do
Copy code
// declared top level
val supervisor = SupervisorJob()
private val motionScope = CoroutineScope(supervisor + EmptyCoroutineContext)
private var motionTimer: Job? = null

  private suspend fun updateMotionTimer() {
    motionTimer?.cancel()
    motionTimer = motionScope.launch {
      val motionDirectory = // Getting the path
      delay(RECORDING_DURATION_AFTER_MOTION_IN_SECONDS.seconds)
      if (isActive) {
        closeMotion(motionDirectory)
      }
    }
  }
o

octylFractal

08/10/2020, 7:31 PM
if you're adding to
filesBeingWritten
and reading it from a different thread, it might have concurrency issues -- I'm not clear if your code is written in a way that avoids that
p

Pacane

08/10/2020, 7:32 PM
in the code above I copied the list specifically to avoid this, but maybe I'm not doing it right
o

octylFractal

08/10/2020, 7:33 PM
copying doesn't avoid that? you have to ensure that the thing that writes to the list is entirely finished and not running by the time you're accessing it
otherwise, since it's not synchronized, data race can occur and all sorts of things can happen, it's unspecified behavior
p

Pacane

08/10/2020, 7:34 PM
well it's an ever-running process, so it's never really finished
right, I should probably use a synchronized collection
this whole thing is a motion detection algorithm for a security camera, so it's in an infinite loop
s

Sam Garfinkel

08/11/2020, 8:55 PM
@Pacane Your use-case is the exact problem solved by a Channel: https://kotlinlang.org/docs/reference/coroutines/channels.html#fan-out
If you don’t want to concurrently read from the channel and write to the FS, just use a standard channel--producer/consumer.
a

asad.awadia

08/17/2020, 5:46 PM
this is like mutating the array while iterating over it
4 Views