Python 3.4 asyncio task doesn't get fully executed -
i'm experimenting python 3.4's asyncio module. since there's no production ready package mongodb using asyncio, have written small wrapper class execute mongo queries in executor. wrapper:
import asyncio functools import wraps pymongo import mongoclient class asynccollection(object): def __init__(self, client): self._client = client self._loop = asyncio.get_event_loop() def _async_deco(self, name): method = getattr(self._client, name) @wraps(method) @asyncio.coroutine def wrapper(*args, **kwargs): print('starting', name, self._client) r = yield self._loop.run_in_executor(none, method, *args, **kwargs) print('done', name, self._client, r) return r return wrapper def __getattr__(self, name): return self._async_deco(name) class asyncdatabase(object): def __init__(self, client): self._client = client self._collections = {} def __getitem__(self, col): return self._collections.setdefault(col, asynccollection(self._client[col])) class asyncmongoclient(object): def __init__(self, host, port): self._client = mongoclient(host, port) self._loop = asyncio.get_event_loop() self._databases = {} def __getitem__(self, db): return self._databases.setdefault(db, asyncdatabase(self._client[db]))
i want execute inserts asynchronously, meaning coroutine executes them doesn't want wait execution complete. asyncio manual states a task automatically scheduled execution when created. event loop stops when tasks done.
, constructed test script:
from asyncdb import asyncmongoclient import asyncio @asyncio.coroutine def main(): print("started") mongo = asyncmongoclient("host", 27017) asyncio.async(mongo['test']['test'].insert({'_id' : 'test'})) print("done") loop = asyncio.get_event_loop() loop.run_until_complete(main())
when run script following result:
started done starting insert collection(database(mongoclient('host', 27017), 'test'), 'test')
there should line indicating mongo query done. can see line when yield from
coroutine instead of running using asyncio.async
. however, what's odd test entry exists in mongodb when run corouting using asyncio.async
, despite fact seems work, don't understand why can't see print statement indicating query has been preformed. despite fact run event loop using run_until_completed
, should wait insert task complete, if main coroutine finished before.
asyncio.async(mongo...))
schedules mongo query. , run_until_complete()
doesn't wait it. here's code example shows using asyncio.sleep()
coroutine:
#!/usr/bin/env python3 import asyncio contextlib import closing timeit import default_timer timer @asyncio.coroutine def sleep_broken(n): # schedule coroutine; runs on next yield asyncio.async(asyncio.sleep(n)) @asyncio.coroutine def sleep(n): yield asyncio.sleep(n) @asyncio.coroutine def double_sleep(n): f = asyncio.async(asyncio.sleep(n)) yield asyncio.sleep(n) # first sleep started yield f n = 2 closing(asyncio.get_event_loop()) loop: start = timer() loop.run_until_complete(sleep_broken(n)) print(timer() - start) loop.run_until_complete(sleep(n)) print(timer() - start) loop.run_until_complete(double_sleep(n)) print(timer() - start)
output
0.0001221800921484828 2.002586881048046 4.005100341048092
output shows run_until_complete(sleep_broken(n))
returns in less 2 milliseconds instead of 2 seconds. , run_until_complete(sleep(n))
works should: returns in 2 seconds. double_sleep()
shows coroutines scheduled async.async()
run on yield from
(two concurrent sleeps in parallel) i.e., sleep 2 seconds, not 4. if add delay (without allowing event loop run) before first yield from
see yield f
doesn't return sooner i.e., asyncio.async
doesn't run coroutines; schedules them run.
Comments
Post a Comment