gpt4 book ai didi

Python 3.4 asyncio 任务没有完全执行

转载 作者:太空狗 更新时间:2023-10-30 00:02:55 29 4
gpt4 key购买 nike

我正在试验 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 手册指出 任务在创建时会自动安排执行。当所有任务完成时,事件循环停止。,所以我构建了这个测试脚本:

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 运行它时,我可以看到那一行。然而,真正奇怪的是,当我使用 asyncio.async 运行这个协程时,测试条目实际上存在于 MongoDB 中,所以尽管它似乎有效,但我不明白为什么不能我看到打印语句表明查询已执行。尽管我使用 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)

输出

0.0001221800921484828
2.002586881048046
4.005100341048092

输出显示 run_until_complete(sleep_BROKEN(n)) 在不到 2 毫秒而不是 2 秒内返回。 run_until_complete(sleep(n)) 正常工作:它会在 2 秒内返回。 double_sleep() 显示由 async.async() 调度的协程在 yield from 上运行(两个并发 sleep 是并行的)即,它 sleep 2 秒,而不是 4 秒。如果您在第一个 yield from 之前添加延迟(不允许事件循环运行),那么您会看到 yield from f 没有尽快返回,即 asyncio.async 不运行协程;它只安排它们运行。

关于Python 3.4 asyncio 任务没有完全执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23180889/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com