You are currently viewing I don’t understand Coroutines at all

I don’t understand Coroutines at all

Hello everyone,

I’ve been trying to convert my tcp server application to use coroutines. The current setup is basically creating a thread for every client that connects to the socket. Of course that’s not really scalable, so I first thought about creating a threadpool and do scheduling via callbacks, but then I wanted to try using coroutines instead, since they seem to be a good solution to my problem.

But even after now two weeks of experimenting I still don’t understand how to use them correctly in my case. This isn’t really helped by the fact that like 95% of online tutorials regarding them focus on Android UI development.

So my basic Setup is this:

My main functions starts two different Servers. They’re mostly decoupled from each other, but for performance reasons they’re still in the same applications so that they can easily communicate with each other via Channels.

Note: This is mostly just pseudo code atm. If it’s needed, I’ll update this to be more reflective of my actual implementation.

According to the documentation, this seems to be they correct way to do this:


fun main() = runBlocking { //initialize database connections and other stuff ... launch { startServer1() } launch { startServer2() } }

Now in e.g. Server1 I want to do an accept loop, which I imagine should look like this:


suspend fun startServer1() { val socket = createSocket() while(true) { val client = socket.accept() launch { handleUser(client) } } }

FYI: I’m using ktor sockets.

But now I’m already at a blocker: I need a coroutineScope to use launch. Am I supposed to pass

this

in main to the startServer functions? But what if I want to use a threadpool? Seems like I can create one with

Executors.newFixedThreadPool(someNumber).asCoroutineDispatcher()

. But what if I wanted to use this again somewhere further down the stack? Should I create a global context variable and then instead of

launch

call

withContext(myThreadPool)

? Or should all my functions that would want to call launch take the callers context as an argument?

Or am I not supposed to use

launch

et al and just run everything with normal function calls? But that would obviously block (I tested this by using a

delay()

in the

handleUser()

function).

I’m honestly at my wits end. Are coroutines maybe just not made for this scenario? Am I fundamentally misunderstanding how they work? I just want to have a threadpool that transparently schedules all my connected clients.

Any help would be appreciated.

submitted by /u/weeblay
[link] [comments]