How to lock two coroutines but allow original coroutine to enter - kotlin

I launch a Coroutine to do some work. I need this to have a mutex. However, sometimes the doWork function calls one() again but a deadlock happens.
private val scope = CoroutineScope(Dispatchers.IO)
private val a = A()
fun start() {
scope.launch {
a.one()
}
}
Then
class A {
private val mutex = Mutex()
suspend fun one() {
mutex.withLock {
doWork()
}
}
}
What I am doing causes a deadlock, because the one() is already locked. Ideally I would get something like #Synchronized in Java which lets the same thread come in, but I know Coroutines are not threads.
Is there anything I can use to solve this? I cannot change the problem too much because some of this code I cannot change myself.

Use communicating coroutines
You said you can't change some of the code, so this solution may not be an option for you. Locks aren't often a good fit with coroutines, though. A more idiomatic solution is to manage your shared resources by having different coroutines communicate with one another.
Instead of using a lock, you make it so that only one coroutine is ever allowed to access the shared resource. Other coroutines may send it work to do, but they may not access the shared resource directly. This guarantees that only one thing ever accesses the shared resource at any given time.
Say our shared resource is a function doSomething() that isn't thread-safe and should only be called by one thread at a time. We launch an actor coroutine that will receive requests. This coroutine is the 'owner' of the shared resource. Anything that wants to call doSomething() must do so by sending a request to this actor. Many things may send requests to the actor, but it will process the requests one at a time. Each time the actor receives a request, it simply calls the doSomething() function. Here I've used a Request class which can contain whatever parameters you need to pass to the shared function. It looks like this:
data class Request(...)
fun start() {
val requests = scope.actor<Request> {
consumeEach { request ->
doSomething(request)
}
}
scope.launch {
requests.send(Request(...))
}
}
suspend fun doSomething(request: Request) {
// do some non-thread-safe work
}

Related

Can I tell Retrofit to ignore OkHttp Dispatcher?

I have a situation in an app, where there are a lot of network calls of the same endpoint (with different parameters) at the same time. This can cause other calls to be blocked.
The setup uses Retrofit + Kotlin Coroutines.
One solution I can think of is to run the calls with different instances of Retrofit+OkHttp using separate thread pools.
However, I'd prefer a single thread pool (and Retrofit instance) defining limitations via different kotlin coroutine dispatchers and the use of limitedParallelism().
See this code snippet:
class NetworkApi(
private val retrofitWebserviceApi: RetrofitWebserviceApi,
threadPoolExecutor: ThreadPoolExecutor,
private val dispatcher: CoroutineDispatcher = threadPoolExecutor.asCoroutineDispatcher()
.limitedParallelism(CoroutineDispatcherConfig.ioDispatcherLimit),
// A separate IO dispatcher pool so the many calls to getEntries don't block other calls
private val noParallelismDispatcher: CoroutineDispatcher = dispatcher.limitedParallelism(1),
) {
/**
* Represents an endpoint, which needs to be called with a lot of different
* parameters at the same time (about 1000 times).
* It's important these calls don't block the whole thread pool.
*/
suspend fun getEntries(description: String) = withContext(noParallelismDispatcher) {
retrofitWebserviceApi.getEntries(description)
}
/**
* This call should not be blocked by [getEntries] calls, but be executed shortly after it is called.
*/
suspend fun getCategories() = withContext(dispatcher) {
retrofitWebserviceApi.getCategories()
}
}
Full executable JVM code sample here: github sample code - question branch
So the idea here is to limit parallel requests using Kotlin Coroutine Dispatchers.
However, the project logs show that OkHttp uses its own OkHttp Dispatcher.
Is there a way to de-activate the OkHttp Dispatcher and just run a network call in the current thread (defined by a Coroutine Dispatcher here)?
Is this possible without losing the possibility to cancel requests?
Thanks for your help!
To use another dispatcher I think you need to remove suspend modifiers in RetrofitWebserviceApi for functions you want to use another dispatcher for:
internal interface RetrofitWebserviceApi {
#GET("entries")
fun getEntries(#Query("description") description: String): EntriesResponse
#GET("categories")
fun getCategories(): CategoriesResponse
}
Custom dispatcher can be set to OkhttpClient as below
private fun createDispatcher(): Dispatcher {
val dispatcher = Dispatcher(Executors.newCachedThreadPool())
dispatcher.maxRequests = 100
dispatcher.maxRequestsPerHost = 100
return dispatcher
}
private fun getOkHttpClient() = OkHttpClient.Builder()
.addInterceptor(getLoggingInterceptor())
.dispatcher(createDispatcher())
.build()
Short answer:
Yes, the OkHttp dispatcher is ignored if Retrofit calls are executed in a synchronuous way.
Long answer:
I went the same way Sergio suggested.
Besides removing the suspend keyword it's necessary to wrap the result type with Call
internal interface RetrofitWebserviceApi {
#GET("entries")
fun getEntries(#Query("description") description: String): Call<EntriesResponse>
#GET("categories")
fun getCategories(
): Call<CategoriesResponse>
}
Defining a Call<T> return type is the canonical way to define Retrofit interfaces and provides 2 options:
Synchronuous exection calling execute() on the Call object. This returns Response<T>.
Asynchronous execution calling enqueue(). This provides T in the callback.
I needed to go with option 1.
Now, the OkHttp thread pool is ignored. The caller side is now responsible to dispatch the execution of the network call to a background thread.
That was my original intention.
The functions in NetworkApi now additionally need to call execute() and body() to obtain the result:
suspend fun getEntries(description: String) =
retrofitWebserviceApi.getEntries(description)
.executeWithDispatcher(noParallelismDispatcher)
suspend fun getCategories() =
retrofitWebserviceApi.getCategories()
.executeWithDispatcher(dispatcher)
private suspend fun <T> Call<T>.executeWithDispatcher(dispatcher: CoroutineDispatcher): T =
withContext(dispatcher)
{
val response = execute()
if (response.isSuccessful) {
checkNotNull(response.body())
} else {
throw HttpException(response)
}
}
Full solution code sample

Kotlin Coroutines - Different options for using Coroutine Scope/Context?

I'm new to Kotlin/Coroutines and I've noticed two different ways to use CoroutineScope.
Option 1 is as follows, within any function:
CoroutineScope(Dispatchers.Default).launch {
expensiveOperation()
}
Option 2 is by implementing the CoroutineScope interface in your class, overriding the CoroutineContext, and then you can just launch coroutines easily with launch or async:
#Service
class ServiceImpl() : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Default + Job()
fun someFunction() {
launch {
expensiveOperation()
}
}
}
I am currently developing a backend endpoint that will do the following:
take a request
save the request context to a database
launch a non blocking coroutine in the background to perform an expensive/lengthy operation on the request, and immediately return an http 200. (essentially, once we have the context saved, we can return a response and let the request process in the background)
What is the difference in the two use cases, and for this scenario, which is the preferred method for obtaining a CoroutineScope?
This endpoint may receive multiple requests per second, and the lengthy operation will take a minute or two, so there will definitely be multiple requests processing at the same time, originating from various requests.
Also, if it's option 2, do I want to pass the scope/context to the function that does the heavy processing? Or is that unnecessary? For example:
class ServiceImpl() : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Default + Job()
fun someFunction() {
launch {
expensiveOperation(CoroutineScope(coroutineContext))
}
}
private fun expensiveOperation(scope: CoroutineScope)
{
// perform expensive operation
}
}
This is a Spring Boot app, and I'm using version 1.3 of Kotlin.
Please let me know if you have any thoughts/suggestions on how to best structure this service class. Thanks
I would recommend option 2. It will give you chance to clearly define parent Job for all of your coroutines. That gives a chance to shut down the whole execution correctly too.
There are several more coroutine context keys to include - CoroutineName, CoroutineExceptionHandler and so one.
Lastly, the structural concurrency may work better if you pass the CoroutineScope and the associated Job explicitly.
https://medium.com/#elizarov/structured-concurrency-722d765aa952
Also, take a look the explanation on that from Roman:
https://medium.com/#elizarov/coroutine-context-and-scope-c8b255d59055

How can I return an awaited value in Kotlin?

I need test() to return a player from my db. I know I can use a callback but how can I make this work with async await?
fun test(): Player {
launch(UI) {
val player = async(CommonPool) { MainActivity.database?.playerDao()!!.loadPlayer() }.await()
return player
}
}
Currently the error is return is not allowed here
In JavaScript for example I would make test async then await it's result from where it's called.
It is impossible to run a coroutine on a raw thread. At the very least you must turn an existing thread into one that spins a top-level event loop. You achieve this with a runBlocking call on the very top of the thread's call stack (i.e., inside its run() method).
On a GUI thread or any other kind of thread that runs an event loop, you need a matching Dispatcher that submits coroutines to this event loop. Kotlin already provides dispatchers for Swing, JavaFX, Android etc. In these cases you need to launch a coroutine from some existing GUI event handler, like this:
myScope.launch {
val player = test()
... use the player ...
}
myScope must be an object that implements CoroutineScope with something like this:
override val coroutineContext = Dispatchers.Main + SupervisorJob()
This will give you a way to cleanly cancel all the coroutines running within the same scope, by calling
coroutineContext[Job]!!.cancel()
My example uses the Main dispatcher, which resolves to the GUI thread when you import the Kotlin coroutines library matching your UI framework.
The test() function must become a suspend fun that temporarily switches the dispatcher to a thread pool for blocking operations. Here's how a basic example could look:
suspend fun test() = withContext(Dispatchers.IO) {
MainActivity.database?.playerDao()!!.loadPlayer()
}
Finally, note I don't mention async at all in this answer. Kotlin's async has a very specific purpose, it is not a general facility like in other languages. Its purpose is strictly parallel decomposition, where you decompose a single task into several concurrent subtasks.

Convey intended thread type (IO, default, main) when declaring suspend function

When designing an API with a suspend function, sometimes I want to convey that this function should be called on, say, an IO thread. Other times that it is essential to do so.
Often it seems obvious; for example a database call should be called using Dispatchers.IO but if it's an interface function, then the caller cannot assume this.
What is the best approach here?
If the suspend function really must run in a specific context, then declare it directly in the function body.
suspend fun doInIO() = withContext(Dispatchers.IO) {
}
If the caller should be able to change the dispatcher, the function can add the dispatcher as a default parameter.
suspend fun doInIO(context: CoroutineContext = Dispatchers.IO) = withContext(context) {
}
There is no strict mechanism for contracts like that, so you are flexible with choosing the mechanism that suits you and your team.
1) Always use withContext(Dispatcher.IO). This is both strict and performant, if a method is invoked from within IO context it will be fast-path'ed.
2) Naming/annotation-based conventions. You can make an agreement in the team that any method which ends with IO or has a specific annotation should be invoked with Dispatchers.IO. This approach works mostly in small teams and only for project-private API. Once you start exporting it as a library/module for other teams such contracts tend to be broken.
3) You can mix the previous approach with a validation:
suspend fun readFile(file: ...) {
require(coroutineContext[ContinuationInterceptor] == Dispatcher.IO) {
"Expected IO dispatcher, but has ${coroutineContext[ContinuationInterceptor]} instead"
}
// read file
}
But this validation works only if you are not wrapping IO dispatcher in some kind of delegate/proxy. In that case, you should make validation aware of such proxies, something like:
fun validateIoDispatcher(dispatcher: ContinuationInterceptor) {
if (dispatcher is Dispatchers.IO) return
if (dispatcher is ProjectSpecificIoDispatcher) return
if (dispatcher is ProjectSpecificWrapperDispatcher) {
validateIoDispatcher(dispatcher.delegate)
} else {
error("Expected IO dispatcher, but has $dispatcher")
}
}
I want to convey that this function should be called on, say, an IO thread. Other times that it is essential to do so.
Not sure what the difference is between "should" and "essential", but having these approaches in mind you can combine it with default method parameters such as suspend fun probablyIO(dispatcher: CoroutineDispatcher = Dispatchers.IO) or more flexible naming/annotation conventions.

does IO in coroutines cause suspension?

Inside a coroutine I am doing a http-request with OkHttpClient. The request is done from a function that has the suspend keyword:
suspend fun doSomethingFromHttp(someParam:String): Something {
...
val response = HttpReader.get(url)
return unmarshalSomething(response)!!
}
I assume that the function can be suspended on entry since it has the suspend keyword, but will the coroutine also be suspended when doing the http-request? What about other kinds of blocking IO?
There's no automagic going on with Kotlin coroutines. If you call a blocking function like HttpReader.get(), the coroutine won't be suspended and instead the call will block. You can easily assure yourself that a given function won't cause the coroutine to suspend: if it's not a suspend function, it cannot possibly do it, whether or not it's called from a suspend function.
If you want to turn an existing blocking API into non-blocking, suspendable calls, you must submit the blocking calls to a threadpool. The easiest way to achieve it is as follows:
val response = withContext(Dispatchers.IO) { HttpReader.get(url) }
withContext is a suspend fun that will suspend the coroutine, submit the provided block to another coroutine dispatcher (here IO) and resume when that block is done and has come up with its result.
You can also easily instantiate your own ExecutorService and use it as a coroutine dispatcher:
val myPool = Executors.newCachedThreadPool().asCoroutineDispatcher()
Now you can write
val response = withContext(myPool) { HttpReader.get(url) }
This PR has example code for proper OkHttp coroutines support
https://github.com/square/okhttp/pull/4129/files
It uses the thread pools of OkHttp to do the work. The key bit of code is this generic library code.
suspend fun OkHttpClient.execute(request: Request): Response {
val call = this.newCall(request)
return call.await()
}
suspend fun Call.await(): Response {
return suspendCancellableCoroutine { cont ->
cont.invokeOnCancellation {
cancel()
}
enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
if (!cont.isCancelled) {
cont.resumeWithException(e)
}
}
override fun onResponse(call: Call, response: Response) {
if (!cont.isCancelled) {
cont.resume(response)
}
}
})
}
}
There are two types of IO libraries in JAVA world, using IO or NIO.
You can find more documentation at https://dzone.com/articles/high-concurrency-http-clients-on-the-jvm
The ones using NIO, can theoretically provide true nonblocking suspension unlike IO ones which only offload the task to a separate thread.
NIO uses some dispatcher threads in the JVM to handle the input output sockets using multiplexing (Reactor design pattern). The way it works is, we request the NIO/dispatchers to load/unload something and they return us some future reference. This code can be turned into coroutines easily.
For IO based libraries, coroutine implementation is not true non blocking. It actually blocks one of the threads just like in Java, however the general usage pattern is, to use Dispatcher.IO which is a threadpool for such blocking IO tasks.
Instead of using OkHttpClient, I would recommend using https://ktor.io/docs/client.html