Coroutines "Asynchronous withTimeout" official tutorial strange behavior - kotlin

In the official guide "Cancellation and timeouts" section "Asynchronous timeout and resources" there is an example that is supposed to... "If you run the above code you'll see that it does not always print zero, though it may depend on the timings of your machine you may need to tweak timeouts in this example to actually see non-zero values."
var acquired = 0
class Resource {
init { acquired++ } // Acquire the resource
fun close() { acquired-- } // Release the resource
}
fun main() {
runBlocking {
repeat(100_000) { // Launch 100K coroutines
launch {
val resource = withTimeout(60) { // Timeout of 60 ms
delay(50) // Delay for 50 ms
Resource() // Acquire a resource and return it from withTimeout block
}
resource.close() // Release the resource
}
}
}
// Outside of runBlocking all coroutines have completed
println(acquired) // Print the number of resources still acquired
}
I do not understand how that work.
If we let the timeout to 60, instances of Resource are never created. We had to go up to 120 to see instances been created.
However 60ms looks enough to let include a delay(50) + an instance creation. No?
Does someone could explain that?
Thanks in advance.

You should not assume these timings are accurate. delay(50) waits for about 50ms and withTimeout(60) timeouts after about 60ms. I believe both of them gives "at least" guarantee, but they may have to wait practically indefinitely. delay() may wait for a longer time than expected, because there are no free threads to resume. withTimeout() may timeout after a longer time, because coroutine does not cooperate for cancelling.
In your case it is possible that it takes more than 50ms for all 100_000 coroutines to get to delay() point. In that case they aren't resumed after 50ms, because they still wait for the thread to become free to handle them. But this is just a guess. Try to replace it with e.g. delay(150) and withTimeout(160).
The main point of this example is that if the timeout happens after the delay has resumed, but before the end of withTimeout() block then exiting from withTimeout() will throw CancellationException. As a result, Resource() will be invoked, but resource.close() won't.

The main reason why instance have no chance to be created is that execution of delay(50) and more generally the whole task take lot of time because 100_000 coroutines competing on the same thread don't let much time to execute in the delay.
So reducing the number of created coroutines to 10 or 100 (a more realistic situation), tasks look to complete quickly, respecting time and timeout.
Here's results
Number of | Created | Still |
coroutines | Resource | Opened |
| instances | Resources |
-----------+-----------+-----------+
100_000 | 0 | - |
10_000 | 8588 | 635 |
1_000 | 1000 | 0 |
100 | 100 | 0 |

Related

delay() effective duration interferences from non parent scopes (unpredictable behaviour?)

Good morning,
I discovered that delay inside a library that make use of coroutines takes way more than the passed value ( which is 5000ms but often takes up to 20 seconds) I initially supposed some library internal issue which was causing continuation to not be called on time.. but I was unable to find that "issue", changed the scope Dispatchers to unconfined in the library changed nothing, ant the cpu usage is very low on all cores ( 5% ) ,
So I've done some tests using the coroutineContext that library ..
The library context is : BLACKBOX_ACTOR.coroutineContext
val threadPool = Executors.newFixedThreadPool(10)
fun busyCoreDelay(ms:Int){ // CONF WORKS ALWAYS
val tstart=System.currentTimeMillis()
while(System.currentTimeMillis()-tstart<ms){
//noop
}
}
withContext( CoroutineName("Test") + Job() +Dispatchers.Unconfined){
GlobalScope.launch(BLACKBOX_ACTOR.coroutineContext+ Job() + Dispatchers.IO+CoroutineName("Test2") ){ // AA with this DOESNTWORKS
//GlobalScope.launch(CoroutineName("Test3") + Job() +Dispatchers.Unconfined){ // AB with this WORKS (only if AA is not present!)
GlobalScope.launch(CoroutineName("Test3") + Job() +threadPool.asCoroutineDispatcher()){ // AC (works with AB , doesn't with AA )
while(isActive){
val tstart=System.currentTimeMillis()
//delay(5000) // PROBLEM1
busyCoreDelay(5000)
val tend=System.currentTimeMillis()
val delaydelta=tend-tstart
log.warn { "inner delaydelta = ${delaydelta}" }
}
}
}
//
}
the main question is why delay takes more than nominal value even when parent is in unconfined Dispatchers ( this is inside the library, the code is complicated to being posted here, but unconfined dispatcher shouldn't avoid delay() calls to take too much (given cpu almost at 0 ? )
but also... why if I call "delay(5000) // PROBLEM1" with AA + AB or AA+AC doesn't works, and with // AB or AB+AC instead works ?
as my understanding the inner job should escape any parent coroutineContext and dispatcher from BLACKBOX_ACTOR
( the busyCoreDelay always works with all configurations )
thank you very much
Gotcha !
The problem was the usage of Dispatchers.Unconfined from an (mine) internal library
this was causing code to be executed on kotlinx.coroutines.DefaultExecutor ,
once any code run on kotlinx.coroutines.DefaultExecutor delay become "unstable"
( it obviously fail to schedule on time given that continuation point is not reached while other code is being executed )
this triggered buggy behaviour in other libraries which timed out upstream calls and so on..
now, I'm gonna mark the question as answered because the problem was actually my mistake in not noticing the use of Dispatchers.Unconfined but It may also be helpful to others
( enable the maximum loglevel and look in the program log for code that is executed on kotlinx.coroutines.DefaultExecutor )
I hope it will also be useful to others who run into the same type of problem,
I want also to thank all the commenters on the original question.

Kotlin Coroutines run synchronously in spite of launch method call

I have a list of employees and I want to hit the API for each of them. In synchronous mode it takes a lot of time and I want to improve the performance with the coroutines. This is what I've done so far:
fun perform() = runBlocking {
employeesSource.getEmployees()
.map { launch { populateWithLeaveBalanceReports(it) } }
.joinAll()
}
suspend fun populateWithLeaveBalanceReports(employee: EmployeeModel) {
println("Start ${COUTNER}")
val receivedReports = reportsSource.getReports(employee.employeeId) // call to a very slow API
receivedReports { employee.addLeaveBalanceReport(it) }
println("Finish ${COUTNER++}")
}
When I try to run this, the code is being run synchronously and in the console I see the following output:
Start 0
Finish 0
Start 1
Finish 1
Start 2
Finish 2
which means that the calls are being done sequentially. If I replace this whole code in the populateWithLeaveBalanceReports function with delay(1000), it will work asynchronously:
Start 0
Start 0
Start 0
Finish 0
Finish 1
Finish 2
What am I doing wrong? Any ideas??
Coroutines don't magically turn your blocking network API into non-blocking. Use launch(Dispatchers.IO) { ... } to run blocking tasks in an elastic thread pool. Just note that this doesn't do much more than the plain-old executorService.submit(blockingTask). It's a bit more convenient because it uses a pre-constructed global thread pool.
These lines might be using a blocking code - the code that relies on blocking threads to wait for task completion.
val receivedReports = reportsSource.getReports(employee.employeeId)
receivedReports { employee.addLeaveBalanceReport(it) }
It is likely that you are using non asynchronous http client or jdbc driver under the hood of reportsSource.getReports call .
If so, you should either
rewrite the code of reportsSource.getReports so it would not rely on any blocking code. This is the new / non-blocking / challenging way
use a threadPool executor to distribute executions manually instead of using coroutines. This is the old / simple way.

Why don't all the shell processes in my promises (start blocks) run? (Is this a bug?)

I want to run multiple shell processes, but when I try to run more than 63, they hang. When I reduce max_threads in the thread pool to n, it hangs after running the nth shell command.
As you can see in the code below, the problem is not in start blocks per se, but in start blocks that contain the shell command:
#!/bin/env perl6
my $*SCHEDULER = ThreadPoolScheduler.new( max_threads => 2 );
my #processes;
# The Promises generated by this loop work as expected when awaited
for #*ARGS -> $item {
#processes.append(
start { say "Planning on processing $item" }
);
}
# The nth Promise generated by the following loop hangs when awaited (where n = max_thread)
for #*ARGS -> $item {
#processes.append(
start { shell "echo 'processing $item'" }
);
}
await(#processes);
Running ./process_items foo bar baz gives the following output, hanging after processing bar, which is just after the nth (here 2nd) thread has run using shell:
Planning on processing foo
Planning on processing bar
Planning on processing baz
processing foo
processing bar
What am I doing wrong? Or is this a bug?
Perl 6 distributions tested on CentOS 7:
Rakudo Star 2018.06
Rakudo Star 2018.10
Rakudo Star 2019.03-RC2
Rakudo Star 2019.03
With Rakudo Star 2019.03-RC2, use v6.c versus use v6.d did not make any difference.
The shell and run subs use Proc, which is implemented in terms of Proc::Async. This uses the thread pool internally. By filling up the pool with blocking calls to shell, the thread pool becomes exhausted, and so cannot process events, resulting in the hang.
It would be far better to use Proc::Async directly for this task. The approach with using shell and a load of real threads won't scale well; every OS thread has memory overhead, GC overhead, and so forth. Since spawning a bunch of child processes is not CPU-bound, this is rather wasteful; in reality, just one or two real threads are needed. So, in this case, perhaps the implementation pushing back on you when doing something inefficient isn't the worst thing.
I notice that one of the reasons for using shell and the thread pool is to try and limit the number of concurrent processes. But this isn't a very reliable way to do it; just because the current thread pool implementation sets a default maximum of 64 threads does not mean it always will do so.
Here's an example of a parallel test runner that runs up to 4 processes at once, collects their output, and envelopes it. It's a little more than you perhaps need, but it nicely illustrates the shape of the overall solution:
my $degree = 4;
my #tests = dir('t').grep(/\.t$/);
react {
sub run-one {
my $test = #tests.shift // return;
my $proc = Proc::Async.new('perl6', '-Ilib', $test);
my #output = "FILE: $test";
whenever $proc.stdout.lines {
push #output, "OUT: $_";
}
whenever $proc.stderr.lines {
push #output, "ERR: $_";
}
my $finished = $proc.start;
whenever $finished {
push #output, "EXIT: {.exitcode}";
say #output.join("\n");
run-one();
}
}
run-one for 1..$degree;
}
The key thing here is the call to run-one when a process ends, which means that you always replace an exited process with a new one, maintaining - so long as there are things to do - up to 4 processes running at a time. The react block naturally ends when all processes have completed, due to the fact that the number of events subscribed to drops to zero.

Usage of WorkspaceJob

I have an eclipse plugin which has some performance issues. Looking into the progress view sometimes there are multiple jobs waiting and from the code most of it's arhitecture is based on classes which extend WorkspaceJobs mixed with Guava EventBus events. The current solution involves also nested jobs...
I read the documentation, I understand their purpose, but I don't get it why would I use a workspace job when I could run syncexec/asyncexec from methods which get triggered when an event is sent on the bus?
For example instead of creating 3 jobs which wait one for another, I could create an event which triggers what would have executed Job 1, then when the method is finished, it would have sent a different event type which will trigger a method that does what Job 2 would have done and so on...
So instead of:
WorkspaceJob Job1 = new WorkspaceJob("Job1");
Job1.schedule();
WorkspaceJob Job2 = new WorkspaceJob("Job2");
Job2.schedule();
WorkspaceJob Job1 = new WorkspaceJob("Job3");
Job3.schedule();
I could use:
#Subsribe
public replaceJob1(StartJob1Event event) {
//do what runInWorkspace() of Job1 would have done
com.something.getStaticEventBus().post(new Job1FinishedEvent());
}
#Subsribe
public replaceJob2(Job1FinishedEvent event) {
//do what `runInWorkspace()` of Job2 would have done
com.something.getStaticEventBus().post(new Job2FinishedEvent());
}
#Subsribe
public replaceJob3(Job2FinishedEvent event) {
//do what `runInWorkspace()` of Job3 would have done
com.something.getStaticEventBus().post(new Job3FinishedEvent());
}
I didn't tried it yet because I simplified the ideas as much as I could and the problem is more complex than that, but I think that the EventBus would win in terms of performance over the WorkspaceJobs.
Can anyone confirm my idea or tell my why this I shouldn't try this( except for the fact that I must have a good arhitecture of my events)?
WorkspaceJob delays resource change events until the job finishes. This prevents components listening for resource changes receiving half completed changes. This may or may not be important to your application.
I can't comment on the Guava code as I don't know anything about it - but note that if your code is long running you must make sure it runs in a background thread (which WorkbenchJob does).

Time out for test cases in googletest

Is there a way in gtest to have a timeout for inline/test cases or even tests.
For example I would like to do something like:
EXPECT_TIMEOUT(5 seconds, myFunction());
I found this issue googletest issues as 'Type:Enhancement' from Dec 09 2010.
https://code.google.com/p/googletest/issues/detail?id=348
Looks like there is no gtest way from this post.
I am probably not the first to trying to figure out a way for this.
The only way I can think is to make a child thread run the function, and if it does not return by the
time limit the parent thread will kill it and show timeout error.
Is there any way where you don't have to use threads?
Or any other ways?
I just came across this situation.
I wanted to add a failing test for my reactor. The reactor never finishes. (it has to fail first). But I don't want the test to run forever.
I followed your link but still not joy there. So I decided to use some of the C++14 features and it makes it relatively simple.
But I implemented the timeout like this:
TEST(Init, run)
{
// Step 1 Set up my code to run.
ThorsAnvil::Async::Reactor reactor;
std::unique_ptr<ThorsAnvil::Async::Handler> handler(new TestHandler("test/data/input"));
ThorsAnvil::Async::HandlerId id = reactor.registerHandler(std::move(handler));
// Step 2
// Run the code async.
auto asyncFuture = std::async(
std::launch::async, [&reactor]() {
reactor.run(); // The TestHandler
// should call reactor.shutDown()
// when it is finished.
// if it does not then
// the test failed.
});
// Step 3
// DO your timeout test.
EXPECT_TRUE(asyncFuture.wait_for(std::chrono::milliseconds(5000)) != std::future_status::timeout);
// Step 4
// Clean up your resources.
reactor.shutDown(); // this will allow run() to exit.
// and the thread to die.
}
Now that I have my failing test I can write the code that fixes the test.