rei*_*ish 6 python python-3.x python-asyncio
我正在试验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]))
Run Code Online (Sandbox Code Playgroud)
我想异步执行插入,这意味着执行它们的协同程序不希望等待执行完成.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())
Run Code Online (Sandbox Code Playgroud)
当我运行脚本时,我得到以下结果:
Started
Done
starting insert Collection(Database(MongoClient('host', 27017), 'test'), 'test')
Run Code Online (Sandbox Code Playgroud)
应该有一行表示mongo查询已完成.当我使用yield from此协程而不是使用它时,我可以看到该行asyncio.async.然而,真正奇怪的是当我运行这个corouting时,测试条目实际上存在于MongoDB中asyncio.async,所以尽管它似乎工作,但我不明白为什么我不能看到指示查询具有的print语句已经预成型.尽管我使用了事件循环run_until_completed,它应该等待插入任务完成,即使主协程已经完成.
asyncio.async(mongo...))只是安排 mongo查询.而run_until_complete()不是等待它.这是使用asyncio.sleep()协同程序显示它的代码示例:
#!/usr/bin/env python3
import asyncio
from contextlib import closing
from timeit import default_timer as timer
@asyncio.coroutine
def sleep_BROKEN(n):
# schedule coroutine; it runs on the next yield
asyncio.async(asyncio.sleep(n))
@asyncio.coroutine
def sleep(n):
yield from asyncio.sleep(n)
@asyncio.coroutine
def double_sleep(n):
f = asyncio.async(asyncio.sleep(n))
yield from asyncio.sleep(n) # the first sleep is also started
yield from f
n = 2
with closing(asyncio.get_event_loop()) as 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)
Run Code Online (Sandbox Code Playgroud)
0.0001221800921484828
2.002586881048046
4.005100341048092
Run Code Online (Sandbox Code Playgroud)
输出显示run_until_complete(sleep_BROKEN(n))返回时间小于2毫秒而不是2秒.run_until_complete(sleep(n))并按预期工作:它在2秒后返回.double_sleep()显示调度的协同程序async.async()运行yield from(两个并发睡眠是并行的),即它睡眠2秒,而不是4.如果你在第一个之前添加一个延迟(不允许事件循环运行),yield from那么你看到yield from f没有返回更快,即asyncio.async不运行协同程序; 它只安排它们运行.
| 归档时间: |
|
| 查看次数: |
1757 次 |
| 最近记录: |