Kotlin Coroutines: runBlocking vs. coroutineScope - multithreading

I am playing around with Kotlin Coroutines, and I ended up in a situation I do not understand. Let's say that I have two suspend functions:
suspend fun coroutine() {
var num = 0
coroutineScope {
for (i in 1..1000) {
launch {
delay(10)
num += 1
}
}
}
println("coroutine: $num")
}
and:
suspend fun runBlocked() = runBlocking {
var num = 0
for (i in 1..1000) {
launch {
delay(10)
num += 1
}
}
println("Run blocking: $num")
}
Then I call them from main() method:
suspend fun main() {
coroutine()
runBlocked()
}
The coroutine() method prints (as expected) a number that is almost never 1000 (usually between 970 and 999). And I understand why.
What I do not understand is why the runBlocked() function allways prints 0.
coroutine: 998
runBlocked: 0
I tried one more time, this time making a similar function to runBlocked(), with the difference that this time the method is returning a value instead of printing:
suspend fun runBlockedWithReturn(): Int = runBlocking {
var num = 0
for (i in 1..1000) {
launch {
delay(10)
num += 1
}
}
return#runBlocking num
}
And then I called it from the main() method:
suspend fun main() {
val result = runBlockedWithReturn()
println("Run blocking with return: $result")
}
...but the method returned 0.
Why is that? And how do I fix the runBlocked() method to print a number that is close to 1000 instead of 0? What am I missing?

runBlocking must never be called from a coroutine in the first place. Since we are violating this contract by putting it in a suspend function, any explanation we have for why it's behaving the way it is might be different on different platforms or in the future.
Aside from that, blocking code should never be called in a coroutine unless you are in a CoroutineContext that uses a dispatcher that can handle it, like Dispatchers.IO.
That said, the reason this is happening is that coroutineScope suspends until all of its children coroutines finish, and runBlocking doesn't. You're launching coroutines out of runBlocking and then immediately returning, so none of those coroutines have necessarily had a chance to even begin running by the time you return num from the function.
If you wanted to wait for all the coroutines launched inside a runBlocking lambda, you need to join() each of them. You can put them in a list and call joinAll() on it. For example:
(1..1000).map {
launch {
delay(10)
num += 1
}
}.joinAll()
But again, runBlocking should never be called in a coroutine. I'm only describing how you would do it if you were using runBlocking from outside a coroutine for its intended purpose, to bridge between non-coroutine and coroutine code.

You should never call runBlocking from inside a suspend fun.
In any event, you don't wait for the launched coroutines to finish before you return a value from runBlocking, but your use of coroutineScope forces the launched coroutines in that function to complete before you get to the return.

Existing answers focus on what we should not do, but I think they miss the point, so the main reason why we see the difference.
Both coroutineScope() and runBlocking() guarantee that after exiting the code block all coroutines inside already finished running. But for some reason, I don't know if intentional or not, you wrote both cases differently. In coroutine() example you put println() below coroutineScope() block, so it is guaranteed to run after all children. On the other hand, in runBlocked() you put println() inside runBlocking(), so it runs concurrently to children. Just rewrite your runBlocked() in a similar way to coroutine(), so put println() below runBlocking() and you will see 1000, as you expected.
Another difference between both examples is that by default runBlocking() runs using a single thread while coroutineScope() could use many of them. For this reason coroutineScope() produces a random value which is a result of unsafe sharing of a mutable state. runBlocking() is more predictable. It always produces 0 if println() is inside it, because println() runs before any children. Or it always produces 1000 if println() is below runBlocking(), because children are in fact running one at a time, they don't modify the value in parallel.

Related

Kotlin coroutines in Minecraft spigot plugin

In the docs it says that coroutines are lighter than threads and so I wanted to use a kotlin coroutine instead of the BukkitRunnable.
//Defined as class field
private val scope = coroutineScope(Dispatchers.Default)
//In class method
scope.launch {/* wait some seconds and then change blockdata */}
Calling setBlockData from Dispatchers.Default thread throws an error because the spigot API is not thread safe and you can't call API stuff from a thread other than the main.
java.lang.IllegalStateException: Asynchronous block remove!
I was thinking that changing block data is the equivalent of android UI changes in Minecraft which means that the coroutine needs to be run/injected into the main thread. So it would make sense to run my coroutine in Dispatchers.Main. However, I can't find a way use Dispatchers.Main and set it to the main thread without getting an illegalStateException
I hope my logic is correct here
If you want a simple method that is able to bridge the suspending code with the main thread (with the possibility of fetching some information from the main thread and use that on your coroutine), you can use this method:
suspend fun <T> suspendSync(plugin: Plugin, task: () -> T): T = withTimeout(10000L) {
// Context: The current coroutine context
suspendCancellableCoroutine { cont ->
// Context: The current coroutine context
Bukkit.getScheduler().runTask(plugin) {
// Context: Bukkit MAIN thread
// runCatching is used to forward any exception that may occur here back to
// our coroutine, keeping the exception transparency of Kotlin coroutines
runCatching(task).fold({ cont.resume(it) }, cont::resumeWithException)
}
}
}
I've commented on what context each part of the code is executed so you can visualize the context switch. suspendCancellableCoroutine is a way of getting hold of the continuation object all coroutines use under the hood, so we can manually resume it once the main thread execute our task.
The outer block withTimeout is used so that if the main thread does not complete our task within 10 seconds, our coroutine gives up instead of hanging forever.
And the use is very simple too:
val plugin = // comes from somewhere
// example coroutine scope
CoroutineScope(Dispatchers.Default).launch {
// doing stuff async
// oh no, I need some data from the main thread!
val block = suspendSync(plugin) {
// this code runs on the MAIN thread
Bukkit.getWorld("blah").getBlockAt(0, 0, 0)
}
// back to async here, do stuff with block (just don't MODIFY it async, use more suspendSync if needed)
}
If you have any questions or think I can improve this answer, don't be afraid of letting me know.

Kotlin: Why isn't job.invokeOnCompletion() block running on main thread?

In my Android application I have code that should run periodically in its own coroutine and should be cancelable.
for this I have the following functions:
startJob(): Initializes the job, sets up invokeOnCompletion() and starts the work loop in the respective scope
private fun startJob() {
if (::myJob.isInitialized && myJob.isActive) {
return
}
myJob= Job()
myJob.invokeOnCompletion {
it?.message.let {
var msg = it
if (msg.isNullOrBlank()) {
msg = "Job stopped. Reason unknown"
}
myJobCompleted(msg)
}
}
CoroutineScope(Dispatchers.IO + myJob).launch {
workloop()
}
}
workloop(): The main work loop. Do some work in a loop with a set delay in each iteration:
private suspend fun workloop() {
while (true) {
// doing some stuff here
delay(setDelayInMilliseconds)
}
}
myJobCompleted: do some finalizing. For now simply log a message for testing.
private fun myJobCompleted(msg: String) {
try {
mainActivityReference.logToGUI(msg)
}
catch (e:Exception){
println("debug: " + e.message)
}
}
Running this and calling myJob.Cancel() will throw the following exception in myJobCompleted():
debug: Only the original thread that created a view hierarchy can touch its views.
I'm curious as to why this code isn't running on the main thread, since startJob() IS called from the main thread?
Furthermore: is there a option similar to using a CancellationTokenSource in c#, where the job is not immediately cancelled, but a cancellation request can be checked each iteration of the while loop?
Immediately breaking off the job, regardless of what it is doing (although it will pretty much always be waiting for the delay on cancellation) doesn't seem like a good idea to me.
It is not the contract of Job.invokeOnCompletion to run on the same thread where Job is created. Moreover, such a contract would be impossible to implement.
You can't expect an arbitrary piece of code to run on an arbitrary thread, just because there was some earlier method invocation on that thread. The ability of the Android main GUI thread to execute code submitted from the outside is special, and involves the existence a top-level event loop.
In the world of coroutines, what controls thread assignment is the coroutine context, while clearly you are outside of any context when creating the job. So the way to fix it is to explicitly launch(Dispatchers.Main) a coroutine from within invokeOnCompletion.
About you question on cancellation, you can use withContext(NonCancellable) to surround the part of code you want to protect from cancellation.

Skipping threads based on parameter, then returning to them later

I have a method that takes in a value and if a condition is met the action shouldn't run for 24 hours. But when it stops I want to run other threads that don't met that condition.
In this example I have 30 threads made at the beginning of the program. Once I make 5 pieces of cheese I need to stop because that's too much cheese. What would be great is if there was a place to send threads that can't be acted on until time is run out while the others are running. Task.Delay even with Wait does not seem to be effective here.
Here's me code sample:
//Stop making cheese when you have enough for the day but continue making others
public void madeEnoughToday(string cheese)
{
//Find how much cheese is made based on cheese type.
DataGridViewRow row = cheeseGV.Rows
.Cast<DataGridViewRow>()
.Where(r =>
r.Cells["Cheese"].Value.ToString().Equals(cheese))
.First();
if (row.Cells["MadeToday"].Value.Equals(row.Cells["Perday"].Value))
{
Task.Delay(30000).Wait();
}
}
When I need to pause thread execution, I use another thread (global variable, or another implementation) - call Thread.Join() method for the second instance of the thread.
Thread tPause; // global var
private void MyThreadFunc()
{
// do something
if (pauseCondition)
{
tPause=new Thread(PauseThread);
tPause.Start();
tPause.Join(); // You can specify needed milliseconds, or TimeSpan
// the subsequent code will not be executed until tPause.IsAlive == true
// IMPORTANT: if tPause == null during Join() - an exception occurs
}
}
private void PauseThread()
{
Thread.Sleep(Timeout.Infinite); // You can specify needed milliseconds, or TimeSpan
}
private void Main()
{
// any actions
Thread myThread=new Thread(MyThreadFunc);
myThread.Start();
// any actions
}
There are many ways of this realization.
If you want to continue the thread execution, you can call the Thread.Abort() method for the pause thread instance, or use the sophisticated construction of function for the pause thread.

thread synchronization: making sure function gets called in order

I'm writing a program in which I need to make sure a particular function is called is not being executed in more than one thread at a time.
Here I've written some simplified pseudocode that does exactly what is done in my real program.
mutex _enqueue_mutex;
mutex _action_mutex;
queue _queue;
bool _executing_queue;
// called in multiple threads, possibly simultaneously
do_action() {
_enqueue_mutex.lock()
object o;
_queue.enqueue(o);
_enqueue_mutex.unlock();
execute_queue();
}
execute_queue() {
if (!executing_queue) {
_executing_queue = true;
enqueue_mutex.lock();
bool is_empty = _queue.isEmpty();
_enqueue_mutex.lock();
while (!is_empty) {
_action_mutex.lock();
_enqueue_mutex.lock();
object o = _queue.dequeue();
is_empty = _queue.isEmpty();
_enqueue_mutex.unlock();
// callback is called when "o" is done being used by "do_stuff_to_object_with_callback" also, this function doesn't block, it is executed on its own thread (hence the need for the callback to know when it's done)
do_stuff_to_object_with_callback(o, &some_callback);
}
_executing_queue = false;
}
}
some_callback() {
_action_mutex.unlock();
}
Essentially, the idea is that _action_mutex is locked in the while loop (I should say that lock is assumed to be blocking until it can be locked again), and expected to be unlocked when the completion callback is called (some_callback in the above code).
This, does not seem to be working though. What happens is if the do_action is called more than once at the same time, the program locks up. I think it might be related to the while loop executing more than once simultaneously, but I just cant see how that could be the case. Is there something wrong with my approach? Is there a better approach?
Thanks
A queue that is not specifically designed to be multithreaded (multi-producer multi-consumer) will need to serialize both eneueue and dequeue operations using the same mutex.
(If your queue implementation has a different assumption, please state it in your question.)
The check for _queue.isEmpty() will also need to be protected, if the dequeue operation is prone to the Time of check to time of use problem.
That is, the line
object o = _queue.dequeue();
needs to be surrounded by _enqueue_mutex.lock(); and _enqueue_mutex.unlock(); as well.
You probably only need a single mutex for the queue. Also once you've dequeued the object, you can probably process it outside of the lock. This will prevent calls to do_action() from hanging too long.
mutex moo;
queue qoo;
bool keepRunning = true;
do_action():
{
moo.lock();
qoo.enqueue(something);
moo.unlock(); // really need try-finally to make sure,
// but don't know which language we are using
}
process_queue():
{
while(keepRunning)
{
moo.lock()
if(!qoo.isEmpty)
object o = qoo.dequeue();
moo.unlock(); // again, try finally needed
haveFunWith(o);
sleep(50);
}
}
Then Call process_queue() on it's own thread.

F#: purpose of SwitchToThreadPool just before async return

In the MS docs for Async.SwitchToNewThread one of the examples given is:
let asyncMethod f =
async {
do! Async.SwitchToNewThread()
let result = f()
do! Async.SwitchToThreadPool()
return result
}
What is the purpose of switching to the thread pool immediately before a return statement? I understand why you might want to switch from a dedicated thread to the thread pool when the async block has more work to do but that is not the case here.
This is not part of the main question, but I'm also curious to know why SwitchToNewThread and SwitchToThreadPool return an Async. Is there ever a use case where you would not want to immediately "do!" these tasks? Thank you
The example could be clearer, because it doesn't demonstrate any real scenario.
However, there is a good reason for switching to another thread before return. The reason is that the workflow that calls your function (e.g. asyncMethod) will continue running in the context/thread that you switch to before returning. For example, if you write:
Async.Start (async {
// Starts running on some thread (depends on how it is started - 'Async.Start' uses
// thread pool and 'Async.StartImmediate' uses the current thread
do! asyncMethod (fun () ->
Thread.Sleep(1000) ) // Blocks a newly created thread for 1 sec
// Continues running on the thread pool thread
Thread.Sleep(1000) }) // Blocks thread pool thread
I think the pattern used in the example isn't quite right - asynchronous workflows should always return back to the SynchronizationContext on which they were started (e.g. if a workflow is started on GUI thread, it can switch to a new thread, but should then return back to the GUI thread). If I was writing asyncMethod function, I'd use:
let asyncMethod f = async {
let original = System.Threading.SynchronizationContext.Current
do! Async.SwitchToNewThread()
let result = f()
do! Async.SwitchToContext(original)
return result }
To answer your second question - the reason why SwitchTo operations return Async<unit> and need to be called using do! is that there is no way to switch to a different thread directly. The only points where you get the rest of the workflow as a function (that you can execute on a new thread) is when you use do! or let! The Async<T> type is essentially just some object that gets a function (the rest of the workflow) and can execute it anywhere it wants, but there is no other way to "break" the workflow.

Resources