Code:
import asyncio
async def f1():
print('f1:1')
await asyncio.sleep(2)
print('f1:2')
async def f2():
print('f2:1')
await asyncio.sleep(2)
print('f2:2')
async def f():
await f1()
await f2()
asyncio.run(f())
Result:
f1:1
f1:2
f2:1
f2:2
What I expected is run f1 and f2 concurrently, and with result:
f1:1
f2:1
f1:2
f2:2
So could anyone please give me some suggestion?
Use gather():
import asyncio
async def f1():
print('f1:1')
await asyncio.sleep(2)
print('f1:2')
async def f2():
print('f2:1')
await asyncio.sleep(2)
print('f2:2')
async def f():
await asyncio.gather(f1(), f2())
asyncio.run(f())
Related
import asyncio
from aiohttp import ClientSession
async def download(session: ClientSession, link: str):
print("init")
async with session.get(link) as resp:
print("hello")
data = await resp.content.read()
print("bye")
return
async def amain():
link = "https://www.google.com/"
async with ClientSession() as session:
tasks = []
for _ in range(100_000):
tasks.append(asyncio.create_task(download(session, link)))
await asyncio.sleep(0) # <------------ Label 1
await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(amain())
If u comment "Label 1" line, u got unexpected output like:
init
init
...
...
init
and then mixed 'hello' and 'bye' as expected.
but if that line uncommented we got 'init' 'hello' 'bye' mixed as u expected from async tasks.
Can anybody explain me, why async with session.get(link) as resp: block task until all tasks created, if they created without await asyncio.sleep(0)?
↓↓↓ works unexpected too:
async def amain():
link = "https://www.google.com/"
async with ClientSession() as session:
await asyncio.gather(*(download(session, link) for _ in range(100_000)))
I have two coroutines one of which is using aioschedule. This is my code
import aioschedule as schedule
import asyncio
async def foo():
while True:
print('foooooo')
await asyncio.sleep(5)
async def bar():
while True:
print('bar')
await asyncio.sleep(1)
schedule.every(2).seconds.do(bar)
loop = asyncio.get_event_loop()
loop.create_task(schedule.run_pending())
loop.create_task(foo())
try:
loop.run_forever()
except KeyboardInterrupt:
loop.stop()
What i want is it should printed bar every n seconds when other task is running but the output is only foooooo. Am i missing something?
try this:
import aioschedule as schedule
import asyncio
async def foo():
while True:
print('foooooo')
await asyncio.sleep(5)
async def bar():
while True:
print('bar')
await asyncio.sleep(1)
#schedule.every(2).seconds.do(bar) <---removed line
loop = asyncio.get_event_loop()
loop.create_task(schedule.run_pending())
loop.create_task(foo())
loop.create_task(bar()) #<---- added line
try:
loop.run_forever()
except KeyboardInterrupt:
loop.stop()
I am trying to use an async generator as a wrapper for a shared connection
async def mygen():
await init()
connection = await open_connection()
while True:
data = yield
await connection.send(data)
shared_gen = None
async def send_data(data):
global shared_gen
if not shared_gen:
shared_gen = mygen()
await shared_gen.asend(None)
await shared_gen.asend(data)
Is the above code safe from race conditions? Is it possible for two asends to execute concurrently or the second one will block implicitly until the generator is ready in the yield step? Assume connection.send is not concurrency safe.
Update:
Wrote a wrapper to help use safely.
class Locked:
def __init__(self, resource):
self._resource = resource
self._lock = asyncio.Lock()
#contextlib.asynccontextmanager
async def lock(self):
async with self._lock:
yield self._resource
async def send_data(locked_gen, data):
async with locked_gen.lock() as gen:
await gen.asend(data)
async def main():
gen = mygen()
await gen.asend(None)
locked_gen = Locked(gen)
...
Is it possible for two asends to execute concurrently or the second one will block implicitly until the generator is ready in the yield step?
It is not possible for asend to be called concurrently, but trying to do so doesn't result in blocking. Instead, the second one will raise a RuntimeError, as demonstrated by the following example:
import asyncio
async def gen():
while True:
yield
await asyncio.sleep(1)
async def main():
ait = gen()
await ait.asend(None) # start the generator
async def send():
print('sending')
await ait.asend(42)
await asyncio.gather(send(), send())
asyncio.run(main())
To make the send block until the previous one finishes, you need an explicit lock around the await of asend:
async def main():
ait = gen()
await ait.asend(None)
lock = asyncio.Lock()
async def send():
async with lock:
print('sending')
await ait.asend(42)
await asyncio.gather(send(), send())
I have a function that I want to call every minute for instance and my code look like this:
async def fun1():
print('fun1')
await asyncio.sleep(30)
async def fun2():
print('fun2')
await asyncio.sleep(10)
async def fun3():
print('fun3')
async def main():
global loop
loop.create_task(fun1())
loop.create_task(fun2())
while True:
await fun3()
await asyncio.sleep(1)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
but it does not print anything. I would like my function to be called every 10 seconds for instance. It looks like fun2 is waiting for fun1 to finish instead of triggering every 30 seconds and 10 seconds respectively...
Any idea why pelase?
Currently, fun1 and fun2 will only print once each since neither contain a loop. Add a loop to make them each print every 10/30 seconds.
import asyncio
async def fun1():
while True:
print('fun1')
await asyncio.sleep(30)
async def fun2():
while True:
print('fun2')
await asyncio.sleep(10)
async def fun3():
print('fun3')
async def main():
global loop
loop.create_task(fun1())
loop.create_task(fun2())
while True:
await fun3()
await asyncio.sleep(1)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
I would like to use an async check function:
async def check(reaction, user):
await x
return y
await self.bot.wait_for('reaction_add', check=check)
This yields an error message that says the check function isn't awaited:
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: ExtensionFailed: Extension 'cogs.boost' raised an error: SyntaxError: 'await' outside async function
If I change the code to:
async def check(reaction, user):
await x
return y
await self.bot.wait_for('reaction_add', check=await check)
I get the following error message:
TypeError: object function can't be used in 'await' expression
Is there any way to have an async check function? Thanks!
async def predicate(ctx):
# you can use any async code here
result = await stuff()
return result
return commands.check(predicate)
Just add async in from to use await features..
Also when you call the function use Await in front
r = await predicate()
You can use the following code as an example to write an async check:
def mycheck():
async def predicate(ctx):
# you can use any async code here
result = await stuff()
return result
return commands.check(predicate)
More information can be found here: discord.py docs
Try this:
import asyncio
#...
async def your_command(ctx, ...):
async def run():
# you can use await there
return ...
def check(msg):
result = asyncio.create_task(run()) # run the async function
return resul
ctx = self.bot.wait_for("message", check=check)
and there is an example:
import asyncio
#commands.command()
async def test(ctx):
async def run(msg):
await msg.send("This message is not yours!", hidden=True)
return
def check(msg):
if msg.author.id == ctx.author.id:
return True
else:
asyncio.create_task(run(msg))
return False
ctx = await self.bot.wait_for("raw_reaction_add", check=check)
...
This work for me