我正在试验 Python 3.4 的 asyncio 模块。由于没有使用 asyncio 的 MongoDB 生产就绪包,我编写了一个小型包装器类,它在执行程序中执行所有 mongo 查询。这是包装:
import asyncio
from functools import wraps
from 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 from 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]))
我想异步执行插入,这意味着执行它们的协程不想等待执行完成。asyncio 手册指出A task is automatically scheduled for execution when it is created. The event loop stops when all tasks are done.
,所以我构建了这个测试脚本:
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())
当我运行脚本时,我得到以下结果:
Started
Done
starting insert Collection(Database(MongoClient('host', 27017), 'test'), 'test')
应该有一行表明 mongo 查询已完成。当我yield from
使用这个协程而不是使用asyncio.async
. 然而,真正奇怪的是,当我运行这个 corouting using 时,测试条目实际上存在于 MongoDB 中asyncio.async
,所以尽管它似乎有效,但我不明白为什么我看不到指示查询有的打印语句被执行。尽管我使用 运行事件循环run_until_completed
,但它应该等待插入任务完成,即使主协程之前完成。