如何终止事件循环

时间:2018-11-19 04:20:20

标签: python python-3.x python-asyncio

我在django视图中具有以下代码来创建后台任务:

xy

我到底需要做些什么来“杀死”循环?关闭它等的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

您无需首先开始任何事件循环。 concurrent.futures package可以直接访问执行程序,而threading则可以启动单个线程:

# raw thread
import threading

background_task = threading.Thread(
    target=update_contacts, kwargs={
        'email': email,
        'access_token': g.tokens['access_token']
})
background_task.start()

# executor thread pool
from concurrent.futures import ThreadPoolExecutor

my_executor = ThreadPoolExecutor()
my_executor.submit(update_contacts, email=email, access_token=g.tokens['access_token'])

通常,如果您只想启动任务而忽略它,那么Thread会更简单。如果您同时执行许多小任务,则ThreadPoolExecutor会更有效率;它也可以用于自动等待多个任务的完成。

print('start at', time.time())
with ThreadPoolExecutor() as executor:
    executor.submit(time.sleep, 1)
    executor.submit(time.sleep, 1)
    executor.submit(time.sleep, 1)
    executor.submit(time.sleep, 1)
print('done at', time.time())  # triggers after all 4 sleeps have finished

loop.run_in_executor的主要目的是 not 来提供ThreadPoolExecutor。它旨在弥合执行程序阻止代码的执行者和非阻止代码的事件循环之间的差距。没有后者,就根本不需要使用asnycio

import time
import asyncio

def block(delay: float):
    print("Stop! Blocking Time!")
    time.sleep(delay)  # block the current thread
    print("Done! Blocking Time!")

async def nonblock(delay: float):
    print("Erm.. Non-Blocking Time!")
    await asyncio.sleep(delay)
    print("Done! Non-Blocking Time!")

async def multiblock(delay: float):
    loop = asyncio.get_event_loop()
    await asyncio.gather(  # await async natively and sync via executors
        nonblock(delay),
        loop.run_in_executor(None, block, delay),
        nonblock(delay),
        loop.run_in_executor(None, block, delay),
    )

asyncio.run(multiblock(1))

答案 1 :(得分:0)

可以通过在Task对象上调用cancel方法来取消Asyncio任务。运行异步代码的任务(例如使用aiohttp库的任务)将立即被取消。使用run_in_executor运行阻塞代码的任务不会被取消,因为它们在后台的OS线程中运行。

这是不鼓励在异步代码中使用run_in_executor的部分原因,并且仅用作权宜之计,以在异步程序中包括传统阻止代码。 (另一部分是任务数受池所允许的OS线程数的限制,而真正的异步任务数的限制要高得多。)