簡體   English   中英

Python 3.4 asyncio任務沒有完全執行

[英]Python 3.4 asyncio task doesn't get fully executed

我正在試驗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. 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運行它時,我可以看到該行。 然而,真正奇怪的是,當我使用asyncio.async運行這個asyncio.async ,測試條目實際上存在於MongoDB中,所以盡管它看起來有效,但我不明白為什么我看不到print語句表明查詢已經執行。 盡管我使用run_until_completed運行事件循環,但它應該等待插入任務完成,即使主協程已經完成。

asyncio.async(mongo...))只是安排 mongo查詢。 並且run_until_complete()不會等待它。 這是使用asyncio.sleep() coroutine顯示它的代碼示例:

#!/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 (兩個並發睡在平行),即,它睡2秒,沒有4.如果你添加一個延遲(不使事件循環運行)在從那時起第一次yield from之前,你會看到yield from f不會很快返回,即asyncio.async不會運行協同程序; 它只安排它們運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM