Hey guys, So I have a server class which contains ...
# coroutines
o
Hey guys, So I have a server class which contains a map of strings to bots, and theres this function in the server class called runBots() which run all the bots. This is what I have for a implementation:
Copy code
fun runBots() = runBlocking {
        try {
            bots.forEach {
                val one = launch { it.value.setConnection(); }
                one.join()
                delay(3000L)
                if(it.value.running) {
                    it.value.Connect()
                }
            }
        } catch(e: Throwable) {
            bots.forEach { if(!it.value.running) it.value.Connect() }
        }
    }
"bots" here is the map of strings to bots. Each bot has a Connect() function(a async function) which runs the all the bot's main loop. The problem is that the bot doesnt run, after the server class calls it's runBots function.
Copy code
Initialised
Connnected: true
Defined bot
Added bot
[main] Connecting....
[main] Sending nick...
Sending nick: NICK Kraken3635

[main] Sending user...
Sending user: USER Nani 0 * :Nani

[main] Connected!
[DefaultDispatcher-worker-1] I'm now in Connect!
[DefaultDispatcher-worker-1] Entering loop...
e
async you mean you do launch inside Connect?
o
yes each Connect is a loop which runs the internals of each bot, and the declaration of Connect is as such:
Copy code
fun Connect() = GlobalScope.async { ... }
e
i see. you should use structured concurrency:
Copy code
fun CoroutineScope.Connect() = launch { ... }
in this case your
runBlocking
call does not exit until child launches complete whatever they do
in your case, you do launch in different scope, so runBlocking does not have any reason to be running
o
ok, where can i read more about this?
e
o
thnx a lot
o
thnx
g
Yes, Connect with coroutine scope is preferred way to implement this, but you can fix existing code if you
join
result of connect, but to do this in parallel you can replace forEach with map and than call joinAll on list of jobs
e
and replace
async
with
launch
then
g
Only if you need result of operation
Otherwise launch is also fine
e
Copy code
val one = launch { it.value.setConnection(); }
                one.join()
what is the reason behind this?
g
Yes, Sergey was faster :) Also want to ask about this code, it doesn't make sense
o
Also should i make the server class the CoroutineScope main class or should i make the bot class the coroutinescope main class?
g
Actually I really curious why Connect calls launch inside, usually you don't need such code
o
well my purpose was to create a bot's main loop on its own coroutine
g
Why?
Preferred and recommended style to use suspend functions
o
well, to make it run faster maybe, i could initialise many bots and run them parallely then
g
Much better to parallel operation only when you need it
So I would remove launch from Connect and instead move it to your runBoth function
So you explicitly parallel jobs
o
ok
g
Also you avoid problems with global scope
And you don't need any joins in this case
o
ok thanks
g
It uses the same approach as you original code, but has remark about this and then demonstrates recommended approach:
This programming style with async functions is provided here only for illustration, because it is a popular style in other programming languages. Using this style with Kotlin coroutines is strongly discouraged for the reasons that are explained below.
o
yeah its the same page given above
g
Yeah, right