Hi, I'm working on a physics sim ```var canvasRef...
# coroutines
u
Hi, I'm working on a physics sim
Copy code
var canvasRefreshTrigger by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
    while (isActive) {
        awaitFrame()
        
        coroutineScope { <--------------------------------
            launch {
                withContext(Dispatchers.Default) {
                    updateParticles2(particles, startIndex = 0, endIndex = half)
                }
            }
            launch {
                withContext(Dispatchers.Default) {
                    updateParticles2(particles, startIndex = half, endIndex = end)
                }
            }
        }
        canvasRefreshTrigger = !canvasRefreshTrigger
    }
}
Canvas {
    ...draw particles
}
and ofc its paralelizable problem, so I wanna process half of the particles on one CPU core, and the other half on a second core This works, but obviously this will be called every frame, so every 8-16ms I was wondering, since this does seem to create a throw-away coroutine scope in
coroutineScope
, if there is a more light weight, ideally non allocating way while keeping coroutines Or is coroutines a bad idea for such high frequency thing?
z
never use
awaitFrame()
in compose, that's a kotlin thing. Use
withFrameNanos
or
withFrameMillis
you can combine
launch { withContext(context) {} }
to just
launch(context)
but in general launching a new coroutine every frame is not ideal
Not sure it makes sense to wait for frames anyway though if you're just going to do the update on a background thread which might not finish until >1 frame later
u
yea i semi made up the sample, im mostly interested how to not launch a coroutine so often maybe some channel solution? but that would require a sort of barrier, to signal back to the original callsite, right?
z
yea, if you want to sync you probably want something like
Copy code
LaunchedEffect(particleSystem) {
  while (isActive) {
    // This kicks off some work on a background thread and returns
    // immediately.
    // On subsequent iterations of the loop this will run immediately
    // after the frame is done and so this lets the work get started
    // while waiting for the next vsync.
    particleSystem.startUpdatingParticlesForFrame()

    withFrameNanos {
      // This blocks until the update from above is done then returns.
      // This callback is run synchronously before the next frame's
      // composition.
      particleSystem.waitForParticleUpdateToFinish()
    }
  }
}
Where
particleSystem
is some object that synchronizes the work on a background thread. Since you're doing it on every frame, you could launch a coroutine every time but might make more sense to set up a worker pool once and then signal the existing workers every frame or something.
u
by worker pool you mean a threadpool executor? or is there a coroutine way