Suppose I have code like this
async def fetch_text() -> str:
return "text "
async def show_something():
something = await fetch_text()
print(something)
Which is fine. But then I want to clean the data, so I do
async def fetch_text() -> str:
return "text "
def fetch_clean_text(text: str) -> str:
text = await fetch_text()
return text.strip(text)
async def show_something():
something = fetch_clean_text()
print(something)
(I could clean text inside show_something()
, but let's assume that show_something()
can print many things and doesn't or shouldn't know the proper way of cleaning them.)
This is of course a SyntaxError: 'await' outside async function
. But—if this code could run—while the await
expression is not placed inside a coroutine function, it is executed in the context of one. Why this behavior is not allowed?
I see one pro in this design; in my latter example, you can't see that show_something()
's body is doing something that can result in its suspension. But if I were to make fetch_clean_text()
a coroutine, not only would it complicate things but would probably also reduce performance. It just makes little sense to have another coroutine that doesn't perform any I/O by itself. Is there a better way?
As said, await only works inside async function. And await just waits for the promise to settle within the async function.
You can use the await keyword on its own (outside of an async function) within a JavaScript module. This means modules, with child modules that use await , wait for the child module to execute before they themselves run. All while not blocking other child modules from loading.
In this way, an async function without an await expression will run synchronously. If there is an await expression inside the function body, however, the async function will always complete asynchronously. Code after each await expression can be thought of as existing in a .then callback.
You can only usefully await a promise. map will return an array, so you can't usefully await it. If someFunction returns a promise, then the map will return an array of promises, which you could wrap with Promise.
I see one pro in this design; in my latter example, you can't see that show_something()'s body is doing something that can result in its suspension.
That's exactly why it designed this way. Writing concurrent code can be very tricky and asyncio authors decided that it's critically important to always explicitly mark places of suspend in code.
This article explains it in details (you can start from "Get To The Point Already" paragraph).
But if I were to make fetch_clean_text() a coroutine, not only would it complicate things but would probably also reduce performance.
You need coroutines almost exclusively when you deal with I/O. I/O always takes much-much more time than overhead for using coroutines. So I guess it can be said - no, comparing to I/O you already deal with, you won't lose any significant amount of execution time for using coroutines.
Is there a better way?
Only way I can suggest: is to maximally split logic that deals with I/O (async part) from rest of the code (sync part).
from typing import Awaitable
def clean_text(text: str) -> str:
return text.strip(text)
async def fetch_text() -> Awaitable[str]:
return "text "
async def fetch_clean_text(text: str) -> Awaitable[str]:
text = await fetch_text()
return clean_text(text)
async def show_something():
something = await fetch_clean_text()
print(something)
You can only use await
in an async
enviroment. Try changing the function to asnyc
:
import asyncio
whatever = . . .
async def function(param) -> asyncio.coroutine:
await param
asyncio.run(function(whatever))
Simple and easy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With