Imagine the following very common situation: you have written a long and complicated function and realize that some of the code should be extracted into a seperate function for reuse and/or readability. Usually, this extra function call will not change the semantics of your program.
However, now imagine that your function is a coroutine and the code you want to extract contains at least one asyncronous call. Extracting it into a separate function now suddenly changes your programs semantics by inserting a new point on which the coroutine yields, the event loop takes control and any other coroutine could be scheduled in between.
Example before:
async def complicated_func():
foo()
bar()
await baz()
Example after:
async def complicated_func():
foo()
await extracted_func()
async def extracted_func():
bar()
await baz()
In the example before, the complicated_func is guaranteed not to be suspended between calling foo() and calling bar(). After refactoring, this guarantee is lost.
My question is this: is it possible to call extracted_func() such that it is executed immediately as if its code would be inline? Or is there some other way to perform such common refactoring tasks without changing the programs semantics?
After refactoring, this guarantee is lost.
It's actually not.
Is it possible to call extracted_func() such that it is executed immediately as if its code would be inline?
That's already the case.
await some_coroutine() means that some_coroutine is likely to give to control back to the event loop, but it's not going to do so until it actually awaits a future (e.g some I/O operation).
Consider this example:
import asyncio
async def coro():
print(1)
await asyncio.sleep(0)
print(3)
async def main():
loop.call_soon(print, 2)
await coro()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Notice how 2 gets printed between 1 and 3 as expected.
That also means it's possible to freeze the event loop by writing such code:
async def coro():
return
async def main():
while True:
await coro()
In this case, the event loop never gets a chance to run another task.
Related
My code has 2 functions:
async def blabla():
sleep(5)
And
async def blublu():
sleep(2)
asyncio.wait_for as I know can wait for one function like this:
asyncio.wait_for(blublu(), timeout=6) or asyncio.wait_for(blublu(), timeout=6)
What I wan't to do, is to make asyncio wait for both of them, and if one of them ends faster, proceed without waiting for the second one.
Is it possible to make so?
Edit: timeout is needed
Use asyncio.wait with the return_when kwarg:
# directly passing coroutine objects in `asyncio.wait`
# is deprecated since py 3.8+, wrapping into a task
blabla_task = asyncio.create_task(blabla())
blublu_task = asyncio.create_task(blublu())
done, pending = await asyncio.wait(
{blabla_task, blublu_task},
return_when=asyncio.FIRST_COMPLETED
)
# do something with the `done` set
I'm trying to wrap an async function up so that I can use it without importing asyncio in certain files. The ultimate goal is to use asynchronous functions but being able to call them normally and get back the result.
How can I access the result from the callback function printing(task) and use it as the return of my make_task(x) function?
MWE:
#!/usr/bin/env python3.7
import asyncio
loop = asyncio.get_event_loop()
def make_task(x): # Can be used without asyncio
task = loop.create_task(my_async(x))
task.add_done_callback(printing)
# return to get the
def printing(task):
print('sleep done: %s' % task.done())
print('results: %s' % task.result())
return task.result() # How can i access this return?
async def my_async(x): # Handeling the actual async running
print('Starting my async')
res = await my_sleep(x)
return res # The value I want to ultimately use in the real callback
async def my_sleep(x):
print('starting sleep for %d' % x)
await asyncio.sleep(x)
return x**2
async def my_coro(*coro):
return await asyncio.gather(*coro)
val1 = make_task(4)
val2 = make_task(5)
loop.run_until_complete(my_coro(asyncio.sleep(6)))
print(val1)
print(val2)
If I understand correctly you want to use asynchronous functions but don't want to write async/await in top-level code.
If that's the case, I'm afraid it's not possible to achieve with asyncio. asyncio wants you to write async/await everywhere asynchronous stuff happens and this is intentional: forcing to explicitly mark places of possible context switch is a asyncio's way to fight concurrency-related problems (which is very hard to fight otherwise). Read this answer for more info.
If you still want to have asynchronous stuff and use it "as usual code" take a look at alternative solutions like gevent.
Instead of using a callback, you can make printing a coroutine and await the original coroutine, such as my_async. make_task can then create a task out of printing(my_async(...)), which will make the return value of printing available as the task result. In other words, to return a value out of printing, just - return it.
For example, if you define make_task and printing like this and leave the rest of the program unchanged:
def make_task(x):
task = loop.create_task(printing(my_async(x)))
return task
async def printing(coro):
coro_result = await coro
print('sleep done')
print('results: %s' % coro_result)
return coro_result
The resulting output is:
Starting my async
starting sleep for 4
Starting my async
starting sleep for 5
sleep done
results: 16
sleep done
results: 25
<Task finished coro=<printing() done, defined at result1.py:11> result=16>
<Task finished coro=<printing() done, defined at result1.py:11> result=25>
After perusing many docs on AsyncIO and articles I still could not find an answer to this : Run a function asynchronously (without using a thread) and also ensure the function calling this async function continues its execution.
Pseudo - code :
async def functionAsync(p):
#...
#perform intensive calculations
#...
print ("Async loop done")
def functionNormal():
p = ""
functionAsync(p)
return ("Main loop ended")
print ("Start Code")
print functionNormal()
Expected Output :
Start code
Main loop ended
Async loop done
Searched examples where loop.run_until_complete is used, but that will not return the print value of functionNormal() as it is blocking in nature.
asyncio can't run arbitrary code "in background" without using threads. As user4815162342 noted is asyncio you run event loop that blocks main thread and manages execution of coroutines.
If you want to use asyncio and take advantage of using it, you should rewrite all your functions that uses coroutines to be coroutines either up to main function - entry point of your program. This main coroutine is usually passed to run_until_complete. This little post reveals this topic in more detail.
Since you're interested in Flask, take a look Quart: it's a web framework that tries to implement Flask API (as much as it's possible) in terms of asyncio. Reason this project exists is because pure Flask isn't compatible with asyncio. Quart is written to be compatible.
If you want to stay with pure Flask, but have asynchronous stuff, take a look at gevent. Through monkey-patching it can make your code asynchronous. Although this solution has its own problems (which why asyncio was created).
Maybe it's a bit late, but I'm running into a similar situation and I solved it in Flask by using run_in_executor:
def work(p):
# intensive work being done in the background
def endpoint():
p = ""
loop = asyncio.get_event_loop()
loop.run_in_executor(None, work, p)
I'm not sure however how safe this is since the loop is not being closed.
Here is an implementation of a helper function which you can use like this:
result = synchronize_async_helper(some_async_function(parmater1,parameter2))
import asyncio
def synchronize_async_helper(to_await):
async_response = []
async def run_and_capture_result():
r = await to_await
async_response.append(r)
loop = asyncio.get_event_loop()
coroutine = run_and_capture_result()
loop.run_until_complete(coroutine)
return async_response[0]
Assuming the synchronous function is inside an asynchronous function, you can solve it using exceptions.
Pseudo code:
class CustomError(Exception):
pass
async def main():
def test_syn():
time.sleep(2)
# Start Async
raise CustomError
try:
test_syn()
except CustomError:
await asyncio.sleep(2)
I'm practicing asyncio after writing multithreaded code many years.
Noticed something which i find it strange. Both in asyncio and in concurrent there is a Future object.
from asyncio import Future
from concurrent.futures import Future
Guess each onee has it's own role..
My question is if i can transfer concurrent.future.Future to asyncio.Future (or the opposite)?
My question is if i can transfer concurrent.future.Future to asyncio.Future (or the opposite)?
If by "transfer" you mean convert one to the other, yes, it's possible, although bridging the impedance mismatch can take some work.
To convert a concurrent.futures.Future into an asyncio.Future, you can call asyncio.wrap_future. The returned asyncio future is awaitable in the asyncio event loop and will complete when the underlying threading future completes. This is effectively how run_in_executor is implemented.
There is no public functionality to directly convert an asyncio future to concurrent.futures future, but there is the asyncio.run_coroutine_threadsafe function, which takes a coroutine, submits it to an event loop, and returns a concurrent future which completes when the asyncio future does. This can be used to effectively convert any asyncio-awaitable future to concurrent future, like this:
def to_concurrent(fut, loop):
async def wait():
await fut
return asyncio.run_coroutine_threadsafe(wait(), loop)
The returned future will behave like you'd expect from a concurrent future, e.g. its result() method will block, etc. One thing you might want to be careful of is that callbacks added to the concurrent future with add_done_callback run in the thread that marked the future completed, which in this case is the event loop thread. This means that if you add some done callbacks, you need to be careful not to invoke blocking calls in their implementation lest you block the event loop.
Note that calling run_coroutine_threadsafe requires the event loop to actually run in some other thread. (For example, you can start a background thread and have it execute loop.run_forever.)
For the "concurrent future to asyncio future" part, here is an utility I use.
from typing import List, Any
from concurrent.futures.thread import ThreadPoolExecutor
import asyncio
class AsyncThreadPool(ThreadPoolExecutor):
_futures: List[asyncio.Future]
_loop: asyncio.AbstractEventLoop
def __init__(self, max_workers=None):
super().__init__(max_workers)
self._futures = []
def queue(self, fn):
self._loop = asyncio.get_event_loop()
fut = self._loop.create_future()
self._futures.append(fut)
self.submit(self._entry, fn, fut)
def queueAsync(self, coroutine):
def newLoop():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
return loop.run_until_complete(coroutine)
self.queue(newLoop)
def _entry(self, fn, fut: asyncio.Future):
try:
result = fn()
self._loop.call_soon_threadsafe(fut.set_result, result)
except Exception as e:
self._loop.call_soon_threadsafe(fut.set_exception, e)
async def gather(self) -> List[Any]:
return await asyncio.gather(*self._futures)
You can use it like that:
with AsyncThreadPool() as pool:
# Queue some sync function (will be executed on another thread)
pool.queue(someHeavySyncFunction)
# Queue a coroutine that will be executed on a new event loop running on another thread
pool.queue(otherAsyncFunction())
# Gather results (non blocking for your current loop)
res: List[Any] = await pool.gather()
There is a function called wrap_future in asyncio.
Wrap a concurrent.futures.Future object in a asyncio.Future object.
See https://docs.python.org/3/library/asyncio-future.html#asyncio.wrap_future
When using trio and nursery objects, how do you capture any value that was returned from a method?
Take this example from the trio website:
async def append_fruits():
fruits = []
fruits.append("Apple")
fruits.append("Orange")
return fruits
async def numbers():
numbers = []
numbers.append(1)
numbers.append(2)
return numbers
async def parent():
async with trio.open_nursery() as nursery:
nursery.start_soon(append_fruits)
nursery.start_soon(numbers)
I modified it so that each method returns a list. How would you capture the return value so that I could print them?
Currently, there is no built-in mechanism for this. Mostly because we haven't figured out how we would even want it to work, so if you have some suggestions that would be helpful :-).
The thing is, with regular functions, there's exactly one obvious place to access the return value – the caller is waiting, so you hand them the return value, done. With concurrent functions, the caller isn't waiting, so you also need some way to specify where to return it to, when to return it, if there are multiple functions you have to keep track of which one is returning a value, and so on. It's not as simple a concept.
What do you want to do with the return values? Do you want to, say, print them immediately when each function returns? In that case the simplest thing is to do it directly from the tasks:
async def print_fruits():
print(await fruits())
async def print_numbers():
print(await numbers())
async with trio.open_nursery() as nursery:
nursery.start_soon(print_fruits)
nursery.start_soon(print_numbers)
You could even factor this into a helper function:
async def call_then_print(fn):
print(await fn())
async with trio.open_nursery() as nursery:
nursery.start_soon(call_then_print, fruits)
nursery.start_soon(call_then_print, numbers)
Or maybe you want to put them in a data structure to look at later?
results = {}
async def store_fruits_in_results_dict():
results["fruits"] = await fruits()
async def store_numbers_in_results_dict():
results["numbers"] = await numbers()
async with trio.open_nursery() as nursery:
nursery.start_soon(store_fruits_in_results_dict)
nursery.start_soon(store_numbers_in_results_dict)
# This is after the nursery block, so we know that the dict is fully filled in:
print(results["fruits"])
print(results["numbers"])
You can imagine fancier versions of those too – for example, sometimes when you run a lot of tasks in parallel you want to capture exceptions, not just return values, so that some tasks can still succeed even if some of them fail. For that you can use a try/except around each individual function, or the outcome library. Or when each operation finishes you could put its return value into a trio.Queue, so that another task can process the results as they're finished. But hopefully this gives you a good starting point :-)
In this case, simply create the arrays in the parent and pass each to the child that needs it.
More generally, pass an object to the tasks; they can set an attribute on it. You might also add an Event so that the parent can wait for the results to be available.