首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在睡眠暂停之前完成coro中的asyncio.sleep()清理

如何在睡眠暂停之前完成coro中的asyncio.sleep()清理
EN

Stack Overflow用户
提问于 2015-11-10 14:35:13
回答 2查看 1K关注 0票数 2

当这个计数器被另一个计时器事件( count_timer )中断并完成时,我无法清除下面的stop_future(睡眠)。

代码语言:javascript
复制
import asyncio
import datetime
from concurrent.futures import FIRST_COMPLETED

DISPLAY_DT_TIMEOUT = 7
MAX_DISPLAY_COUNT = 3
COUNT_TIMEOUT = 4


def stop(stop_future, display_count):

    print('stop', display_count, datetime.datetime.now())
    stop_future.set_result('Done!')

async def display_dt1():

    display_count = 0
    stop_future = asyncio.Future()
    stop_handle = loop.call_later(DISPLAY_DT_TIMEOUT, stop, stop_future, display_count)

    # loop until
    while not stop_future.done() and display_count < MAX_DISPLAY_COUNT:
        print('dt1-1', display_count, datetime.datetime.now())
        count_timer = asyncio.sleep(COUNT_TIMEOUT)            # cleanup ??
        await asyncio.wait([count_timer, stop_future], return_when=FIRST_COMPLETED)
        print('dt-2', display_count, datetime.datetime.now())
        display_count += 1

    if not stop_future.done():
        # cleanup stop future
        stop_handle.cancel()
        stop_future.cancel()

async def wait_before_loop_close():

    await asyncio.sleep(10)


loop = asyncio.get_event_loop()
coro = display_dt1()
loop.run_until_complete(coro)

# this print shows the count_timer is still pending
print('tasks-1', asyncio.Task.all_tasks())

# wait for the count_timer to finish     
loop.run_until_complete(wait_before_loop_close())

loop.close()
print('tasks-2', asyncio.Task.all_tasks())

print('finished', datetime.datetime.now())

结果:

代码语言:javascript
复制
dt1-1 0 2015-11-10 15:20:58.200107
dt-2 0 2015-11-10 15:21:02.201654
dt1-1 1 2015-11-10 15:21:02.201654
stop 0 2015-11-10 15:21:05.186800      # stop interrupt
dt-2 1 2015-11-10 15:21:05.186800      # results in stop counting
tasks-1 {<Task pending coro=<sleep() running at D:\Python\Python35-32\lib\asyncio\tasks.py:495> wait_for=<Future pending cb=[Task._wakeup()]>>}
>>> tasks-2 set()
finished 2015-11-10 15:21:15.193669

更新-1:取消count_timer (包装在未来)

代码语言:javascript
复制
async def display_dt1():

    count_timer_task = None
    display_count = 0
    stop_future = asyncio.Future()
    stop_handle = loop.call_later(DISPLAY_DT_TIMEOUT, stop, stop_future, display_count)

    while not stop_future.done() and display_count < MAX_DISPLAY_COUNT:
        print('dt1-1', display_count, datetime.datetime.now())
        count_timer = asyncio.sleep(COUNT_TIMEOUT)            # cleanup ??
        count_timer_task = asyncio.ensure_future(count_timer)
        await asyncio.wait([count_timer_task, stop_future], return_when=FIRST_COMPLETED)
        print('dt-2', display_count, datetime.datetime.now())
        display_count += 1

    if count_timer_task and not count_timer_task.cancelled():
        count_timer_task.cancel()
        print('check-1', datetime.datetime.now(), count_timer_task)

    if not stop_future.done():
        stop_handle.cancel()
        stop_future.cancel()
        print('check-2', datetime.datetime.now(), stop_future)

结果:

代码语言:javascript
复制
dt1-1 0 2015-11-10 16:44:29.180372
dt-2 0 2015-11-10 16:44:33.180908
dt1-1 1 2015-11-10 16:44:33.180908
stop 0 2015-11-10 16:44:36.181062
dt-2 1 2015-11-10 16:44:36.181062
check-1 2015-11-10 16:44:36.181062 <Task pending coro=<sleep() running at D:\Python\Python35-32\lib\asyncio\tasks.py:495> wait_for=<Future cancelled>>
tasks-1 set()
>>> tasks-2 set()
finished 2015-11-10 16:44:46.181965
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-11-10 19:23:19

asyncio.wait_for实现了很多您想要做的事情。将其与asyncio.shield结合起来,以防止在超时结束时取消您的未来:

代码语言:javascript
复制
await asyncio.wait_for(asyncio.shield(stop_future), COUNT_TIMEOUT)

编辑:如果不清楚,这会出现在while循环中,取代对asyncio.wait的调用。

用voscausa更新:显示代码

代码语言:javascript
复制
async def display_dt1():

    display_count = 0
    stop_future = asyncio.Future()
    stop_handle = loop.call_later(DISPLAY_DT_TIMEOUT, stop, stop_future, display_count)

    while not stop_future.done() and display_count < MAX_DISPLAY_COUNT:
        print('dt-1', display_count, datetime.datetime.now())
        try:
            await asyncio.wait_for(asyncio.shield(stop_future), COUNT_TIMEOUT)
        except asyncio.TimeoutError:
            print('timeout', datetime.datetime.now())
        print('dt-2', display_count, datetime.datetime.now())
        display_count += 1

    if not stop_future.done():
        stop_handle.cancel()
        stop_future.cancel()
        print('check-2', datetime.datetime.now(), stop_future)

通过以下方式:

代码语言:javascript
复制
DISPLAY_DT_TIMEOUT = 10
MAX_DISPLAY_COUNT = 3
COUNT_TIMEOUT = 4

结果:

代码语言:javascript
复制
dt-1 0 2015-11-10 21:43:04.549782
timeout 2015-11-10 21:43:08.551319   # count timeout
dt-2 0 2015-11-10 21:43:08.551319
dt-1 1 2015-11-10 21:43:08.551319
timeout 2015-11-10 21:43:12.552880   # count timeout
dt-2 1 2015-11-10 21:43:12.552880
dt-1 2 2015-11-10 21:43:12.552880
stop 0 2015-11-10 21:43:14.554649    # stop timeout
dt-2 2 2015-11-10 21:43:14.555650
tasks-1 set()
tasks-2 set()
finished 2015-11-10 21:43:24.558510
票数 3
EN

Stack Overflow用户

发布于 2015-11-10 14:51:50

您已经将wait()配置为在计时器完成或用户取消循环后返回。如果不是将来导致count_timer调用返回,您似乎想要取消wait。您可以简单地通过询问这两种未来中的哪一种来了解这一点。

代码语言:javascript
复制
count_timer = asyncio.sleep(COUNT_TIMEOUT)
await asyncio.wait([count_timer, stop_future], return_when=FIRST_COMPLETED)
if not count_timer.done():
    count_timer.cancel()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33632470

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档