uasyncio.create_task does not run coroutine (micropython) - micropython

Before I start an issue on github, just wanted to know, if I am doing smth wrong. This basic example should start a loop and after one calls the stop method it should stop. However, the print("while loop") gets not executed at all.
rp2040 Zero (Pico)
Thonny IDE
import uasyncio
import utime
class Test:
def __init__(self):
pass
def run_loop(self):
self.should_run = 1
uasyncio.create_task(self._while_loop())
async def _while_loop(self):
print("while loop") # <--------- gets never called!
counter = 0
while self.should_run == 1:
counter += 1
print(counter)
await uasyncio.sleep_ms(100)
def stop(self):
self.should_run = 0
print("should stop now")
test = Test()
test.run_loop()
print("looop started.. wait..")
utime.sleep(3)
print("...waited..")
test.stop()

In a python script all executions are sync by default. To provide async functionality one has to create an async context. this is done via
asyncio.run() // which will wait due to pythons nature till all inner async tasks are terminated.
As the micropython-uasyncio docs says, a typical async application is wrapped into the async context (e.g. main function).
This is how I solved the problem above:
import uasyncio as asyncio
import utime
class Test:
run = 0
def __init__(self):
pass
def run_loop(self):
self.run = 1
asyncio.create_task(self._while_loop())
async def _while_loop(self):
print("while loop, should_run:", self.run)
counter = 0
while self.run == 1:
counter += 1
print(counter)
await asyncio.sleep_ms(100)
def stop(self):
self.run = 0
print("should stop now")
async def main():
test = Test()
test.run_loop()
print("looop started.. wait..")
await asyncio.sleep(2)
test.stop()
asyncio.run(main())

Related

Twitter Futures - how are unused futures handled?

So I have a api in Scala that uses twitter.util.Future.
In my case, I want to create 2 futures, one of which is dependent on the result of the other and return the first future:
def apiFunc(): Future[Response]={
val future1 = getFuture1()
val future2 = future1 map {
resp => processFuture1Resp(resp)
}
future1
}
So in this case, future2 is never consumed and the api returns the result of future1 before future2 is completed.
My question is - will future2 run even though the api has returned?
Further, future1 should not be affected by future2. That is, the processing time for future2 should not be seen by any client that calls apiFunc(). You can think of processFuture1Resp as sending the results of getFuture1() to another service but the client calling apiFunc() doesn't care about that portion and only wants future1 as quickly as possible
My understanding is that futures spawn threads, but I am unsure if that thread will be terminated after the return of the main thread.
I guess a different way to ask this is - Will a twitter.util.future always be executed? Is there a way to fire and forget a twitter.util.future?
If you want to chain two futures where one of them processes the result of the other (and return a future), you can use a for comprehension:
def getFuture1() = {
println("Getting future 1...")
Thread.sleep(1000)
Future.successful("42")
}
def processFuture1Resp(resp: String) = {
println(s"Result of future 1 is: ${resp}")
"END"
}
def apiFunc(): Future[String]={
for {
res1 <- getFuture1()
res2 <- Future(processFuture1Resp(res1))
} yield res2
}
def main(args: Array[String]) {
val finalResultOfFutures: Future[String] = apiFunc()
finalResultOfFutures
Thread.sleep(500)
}
This will print:
Getting future 1...
Result of future 1 is: 42
The value finalResultOfFutures will contain the result of chaining both futures, and you'll be sure that the first future is executed before the second one. If you don't wait for the execution of finalResultOfFutures on the main thread (commenting the last sleep function of the main thread), you will only see:
Getting future 1...
The main thread will finish before the second future has time to print anything.
Another (better) way to wait for the execution of the future would be something like this:
val maxWaitTime: FiniteDuration = Duration(5, TimeUnit.SECONDS)
Await.result(finalResultOfFutures, maxWaitTime)
Await.result will block the main thread and waits a defined duration for the result of the given Future. If it is not ready or completes with a failure, Await.result will throw an exception.
EDITED
Another option is to use Monix Tasks This library allows you wrap actions (such as Futures) and have a greater control on how and when the Futures are executed. Since a Future may start its execution right after its declaration, these functionalities can be quite handy. Example:
import monix.execution.Scheduler.Implicits.global
import scala.concurrent.duration._
def getFuture1() = {
println("Getting future 1...")
Thread.sleep(3000)
println("Future 1 finished")
Future.successful("42")
}
def processFuture1Resp(resp: Task[String]) = {
val resp1 = resp.runSyncUnsafe(2.seconds)
println(s"Future2: Result of future 1 is: ${resp1}")
}
def main(args: Array[String]) {
// Get a Task from future 1. A Task does not start its execution until "run" is called
val future1: Task[String] = Task.fromFuture(getFuture1())
// Here we can create the Future 2 that depends on Future 1 and execute it async. It will finish even though the main method ends.
val future2 = Task(processFuture1Resp(future1)).runAsyncAndForget
// Now the future 1 starts to be calculated. Yo can runAsyncAndForget here or return just the task so that the client
// can execute it later on
future1.runAsyncAndForget
}
This will print:
Getting future 1...
Future 1 finished
Future2: Result of future 1 is: 42
Process finished with exit code 0

Nested Future.sequence executes included Futures sequentially

I have a future(doFour) that is executed and results passed to a flatmap.
Inside the flatmap I execute two more future(doOne and doTwo) functions expecting them to run on parallel but I see they are running sequentially (2.13). Scastie
Why are doOne and doTwo not execute in parallel ?
How can I have them to run in parallel ?
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
object Test {
def doOne(): Future[Unit] = Future {
println("startFirst"); Thread.sleep(3000); println("stopFirst")
}
def doTwo(): Future[Unit] = Future {
println("startSecond"); Thread.sleep(1000); println("stopSecond")
}
def doFour(): Future[Unit] = Future {
println("do 4"); Thread.sleep(1000); println("done 4")
}
def main(args: Array[String]) {
val resOut = doFour().flatMap { a =>
val futureOperations = Seq(doOne(), doTwo())
val res = Future.sequence(futureOperations)
res
}
val stream = Await.result(resOut, Duration.Inf)
}
}
A Future becomes eligible for execution as soon as it is created. So this line creates two Futures that can potentially be executed:
val futureOperations = Seq(doOne(), doTwo())
The call to Future.sequence will create a new Future that waits for each of the futures to complete in turn, but they will both already be available for execution by this point in the code.
val res = Future.sequence(futureOperations)
If you want Futures to start sequentially you need to use map/flatMap:
val res = doOne().map( _ => doTwo())
With this code doTwo will not be called until doOne completes (and not at all if doOne fails)
The reason that this does not appear to happen in your example is that you are calling a blocking operation in your Future which is blocking a thread that would otherwise be used to execute other Futures. So although there are two Futures available for execution, only one is actually being executed at a time.
If you mark the code as blocking it works correctly:
import scala.concurrent.blocking
def doOne(): Future[Unit] = Future {
blocking{println("startFirst"); Thread.sleep(3000); println("stop First")}
}
def doTwo(): Future[Unit] = Future {
blocking{println("startSecond"); Thread.sleep(1000); println("stop Second")}
}
See the comments section for details of why the default behaviour is different on different versions, and why you should never make assumptions about the relative execution order of independent Futures.

In Scala, can a program finishes/exits if one of his Future val is unfinished?

A simple example to illustrate the problem:
1 - Here, does the program exits after the future is completed ?
def main(args: Array[String]): Unit = {
val future: Future[Unit] = myFunction()
}
2 - If not, should I had an Await to guarantee that the future terminates?
def main(args: Array[String]): Unit = {
val future: Future[Unit] = myFunction()
Await.result(future, Inf)
}
Reading this about Futures/Promises in Scala, the point is: it is not the Future that is about concurrency.
Meaning: what prevents the JVM from exiting are running threads. Coming from there: unless something in your code creates an additional thread that somehow prevents the JVM from exiting, your main() should simply end.
Futures are a mean to interact with content which becomes available at some later point in time. You should rather look into your code base to determine what kind of threading comes in place, and for example if some underlying thread pool executor is configured regarding the threads it is using.
A future is value that is returned after executing a piece of task independently by a new thread(mostly) spawned by the another thread(say main).
To answer your question Yes the main thread will exit even if any future is still under execution.
import scala.concurrent._
import ExecutionContext.Implicits.global
object TestFutures extends App{
def doSomeOtherTask = {
Thread.sleep(1000) //do some task of 1 sec
println("Completed some task by "+Thread.currentThread().getName)
}
def returnFuture : Future[Int]= Future{
println("Future task started "+Thread.currentThread().getName)
Thread.sleep(5000) //do some task which is 5 sec
println("Future task completed "+Thread.currentThread().getName)
5
}
val x = returnFuture //this takes 5 secs
doSomeOtherTask // ~ 1 sec job
println(x.isCompleted)
doSomeOtherTask // ~ 2 sec completed
println(x.isCompleted)
doSomeOtherTask // ~ 3 sec completed
println(x.isCompleted)
println("Future task is still pending and main thread have no more lines to execute")
}
Output:-
Future task started scala-execution-context-global-11
Completed some task by main
false
Completed some task by main
false
Completed some task by main
false
Future task is still pending and main thread have no more lines to execute

`akka.pattern.after` - Understanding `duration` Argument?

Using Scala 2.11.8, given a Future that sleeps 5 seconds before returning (), I called akka.pattern.ask with a time-out of 1 second:
import scala.concurrent.duration._
import scala.concurrent._
import akka.actor.ActorSystem
import scala.concurrent.ExecutionContext.Implicits.global
import akka.pattern.after
val system = ActorSystem.create()
after( FiniteDuration(1, SECONDS), system.scheduler)( Future{ Thread.sleep( 5000 ); () } )
res15: scala.concurrent.Future[Unit] = List()
// roughly 5 seconds later, I see:
scala> res15
res22: scala.concurrent.Future[Unit] = Success(())
Why doesn't res15 return a Failure since the Future does not complete until 5 seconds, however its timeout is 1 second?
After method will run your future after some delay. duration is not timeout, its the starting delay. After method internally uses scheduleOnce method of actorSystem schedular.
After is very interesting method which starts evaluating/executing your future expression (i.e value) only after the certain given duration.
If the given duration is very small then its starts executing the value immediately.
As value is a call by name parameter the value is not immediately evaluated. value will be evaluated only when explicitly called by the name value.
Here is the code from akka lib.
def after[T](duration: FiniteDuration, using: Scheduler)(value: ⇒ Future[T])(implicit ec: ExecutionContext): Future[T] =
if (duration.isFinite() && duration.length < 1) {
try value catch { case NonFatal(t) ⇒ Future.failed(t) }
} else {
val p = Promise[T]()
using.scheduleOnce(duration) { p completeWith { try value catch { case NonFatal(t) ⇒ Future.failed(t) } } }
p.future
}
Basically your duration will trigger the following code
using.scheduleOnce(duration) { p completeWith { try value catch { case NonFatal(t) ⇒ Future.failed(t) } } }
The above code will start executing the future after delay(duration is the delay.).
Important observations:
note that value is a call by name parameter. value will be evaluated when called by name that means your future will not be start executing until and unless value is called explicitly. value is called inside try because value could be a multi line expression which contains lot of code and which returns a future finally.
Promise (see in the code) will make you wait in a non blocking fashion till the future is completed its execution. promise.future will only complete when given future completes.

In twitter future, how to set function of asynchronize return directly

I am new to future modern, what I expect from the following code is :
launch future task finished!
end of task
but actualy, the "end of task" appear first.
I want the process in function long_task to run asynchronizely.
what did I missed?
import com.twitter.util.Future
object FutureTest extends App{
def long_task(): Future[_] = { //the function of asynchronize processing
Thread.sleep(5000)
println("end of task")
Future.value("")
}
val f = long_task()
println("launch future task finished!")
}
The problem you are encountering is that long_task is a synchronous function that returns a completed future after it has done all the work. A future in and of itself does not start asynchronous work, but is just a handle for notification of asynchronous. It's still up to you to start the work asynchronously.
For your example using a FutureTask with a java ExecutorService will do the trick:
object FutureTest extends App{
val pool: ExecutorService = Executors.newFixedThreadPool(10)
def long_task(): Future[Unit] = {
// create a FutureTask, which is a Callable wrapped by a Future
val f = new FutureTask[Unit](new Callable[Unit]() {
def call(): Unit = {
Thread.sleep(5000)
println("end of task")
}})
// execute the callable
pool.execute(f)
// return the uncompleted future
f
}
val f = long_task()
println("launch future task finished!")
}
If you can use the scala Future instead of Twitter's the syntax gets a little simpler, since they've abstracted the underlying Threadpool work a bit further:
import scala.concurrent.ExecutionContext.Implicits._
import scala.concurrent.{Await, future}
import scala.concurrent.duration._
object FutureTest extends App {
def long_task() = future {
Thread.sleep(5000)
println("end of task")
}
val f = long_task()
println("launch future task finished!")
Await.result(f,10.seconds)
}
Note the Await at the end, which is needed here because with scala's default executorservice, the future work is a daemon thread which will not keep the runtime from quiting as soon as it reaches the last line. Await forces the program to block until the future completes.
Try it this way (create the Future first and execute):
import com.twitter.util.{Future, FutureTask}
object FutureTest extends App{
def long_task(): Future[_] = new FutureTask { //the function of asynchronize processing
Thread.sleep(5000)
println("end of task")
""
}
val f = long_task()
println("launch future task finished!")
}