Hey everyone.

Nick and I clarified our understanding of coroutines via IRC. Between this
email and IRC, it seems Nick's primary concern is that it may be difficult
to make the FFI libraries internally threadsafe [1]. By default, coroutines
dispatch to the `CommonPool`, where 1) coroutines can be dispatched to
arbitrary common pool threads and 2) an already dispatched coroutine, after
suspension, can resume on an arbitrary thread in the common pool.

Unfortunately, I don't understand the FFI thread safety in Rust issue well
enough to provide a single solution, however, some varied solutions to
thread safety are:
- Coroutines optionally suspend when they call a function with the
`suspend` keyword. afaik, if you never call one of these functions, you'll
never suspend and you'll remain on a single thread. This is hard to
enforce, however.
- Use a single dedicated thread for all FFI calls by running on a dedicated
CoroutineContext: see `newSingleThreadContext
<https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-single-thread-context.html>
`
- (may not be possible) Implement a new
CoroutineContext/CoroutineDispatcher that dispatches to a thread pool but
will resume only on the same thread. CoroutineContexts can be built on top
of Executor, if that's helpful.
- If your problem is sequential calls rather than which actual thread the
coroutines run on, you can use a coroutine `mutex
<https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/index.html>`
which will suspend until the resource can be acquired.

For our raw conversation, see the IRC logs
<https://mozilla.logbot.info/mobile/20180723#c15057582>.

Hope it helps! Please let me know if you have more questions!
- Mike

[1]: https://mozilla.logbot.info/mobile/20180724#c15058851 (and previous
day)

On Fri, Jul 20, 2018 at 9:44 AM Nicholas Alexander <nalexan...@mozilla.com>
wrote:

> Mike,
>
> Thanks so much for teaching us some things.
>
> On Thu, Jul 19, 2018 at 1:20 PM, Michael Comella <mcome...@mozilla.com>
> wrote:
>
>> Thanks for the updates, Nick – it's interesting to hear what other teams
>> are doing and how it may affect me. :) One quick thought:
>>
>>
>>> Rust code should be synchronous
>>
>>
>> I haven't thought about this enough to have an opinion on whether this is
>> the right decision or not. However, this may encourage the Rust library
>> consumers to make a mistake I once made with Kotlin coroutines: *I want
>> to share so others don't make the same mistake.*
>>
>> While you can create an obscenely large number of coroutines, there is a
>> limit to the number that can run concurrently: this limit is defined by the
>> thread pool they run on. The default built-in `CommonPool` has a fixed
>> number of threads. If you run blocking code (e.g. potentially synchronous
>> Rust code ^) on this thread pool, i*t prevents other coroutines from
>> beginning to run* until the blocking code completes. Here's a
>> demonstration using Android.
>> <https://github.com/mcomella/BlockingCoroutinesExample>
>>
>
> I was concerned about this, for slightly different reasons: I care about
> the same thread of execution servicing the next FFI call, i.e., that FFI
> calls don't rotate between threads non-deterministically.  But I think it's
> very similar to the situation you warn about.  I took an action item to
> read more about Kotlin co-routines, and summarized (in the notes) like this:
>
>
>    -
>
>          AI: nalexander to read more about how Kotlin coroutines are
>          implemented
>          -
>
>             [nalexander] OK, I’ve done this.  Based on the Kotlin 1.1+
>             coroutines documentation
>             <https://kotlinlang.org/docs/reference/coroutines.html>,
>             Kotlin coroutines are implemented as a CPS transformation and an 
> internal
>             state machine.  That state machine is pumped from a single 
> thread. That’s
>             very similar to clojure/core.async
>             <https://github.com/clojure/core.async> and means that
>             there’s no thread pool servicing coroutines!  Any additional 
> thread must be
>             the result of the application (or a library).  That means
>             that all my hypothetical concerns about coroutines invoking FFI 
> methods on
>             multiple threads are not justified.
>
> Am I incorrect?  Please correct me if so!
>
> Why is this a problem? *If you're a library (e.g. android-components)
>> that uses the same fixed thread pool as the application, you may block the
>> application's coroutines from starting quickly!* For example, if the
>> library makes several calls to read configuration files from disk, each on
>> a new coroutine on the CommonPool, these may block all of the CommonPool
>> threads. If all the threads are blocked and the application spawns a
>> coroutine on the CommonPool to do background processing before rendering
>> the results in the UI, the application's coroutine (and thus the UI update)
>> will wait until the library's coroutines finish blocking before it runs.
>>
>> ---
>>
>> Some possible solutions to this are:
>> - Use a separate thread pool for blocking calls (here's an open ticket
>> for a system-wide IO thread pool
>> <https://github.com/Kotlin/kotlinx.coroutines/issues/79>)
>> - Use non-blocking IO (supported in Java 7+ with nio
>> <https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-nio/>)
>>
>
> I agree that `CommonPool` can cause issues.  (Just for the record, I had
> not heard of `CommonPool`.)  But to me, those issues are clearly _above_
> the Rust FFI layer, and the _common_ part of the name is pretty clear that
> applications and libraries need to coordinate in order to prevent bad
> things (in this case, limiting throughput due to resource starvation, or,
> in the worst case, livelocking).
>
> Coming back to my summary of how Kotlin coroutines are implemented,
> something above the Rust library layer has to handle adding asynchrony to
> the synchronous Rust -- either by spawning threads (with a pool, common or
> otherwise, if desired); or by doing non-blocking things where possible; or
> ...
>
> Are we in accord?
> Nick
>
>
_______________________________________________
Dev-fxacct mailing list
Dev-fxacct@mozilla.org
https://mail.mozilla.org/listinfo/dev-fxacct

Reply via email to