繁体   English   中英

PIL和使用asyncio阻止呼叫

[英]PIL and blocking calls with asyncio

我有一个异步应用程序,该应用程序使用aiohttp服务器和带有asyncio.open_connection()异步套接字

我的代码包含来自PIL库的一些阻止调用,例如

Image.save()
Image.resize()
  1. 即使呼叫没有阻塞太多时间,但是如果我使用这些阻塞呼叫,我的Web服务器是否可以冻结? 更准确地说,事件循环是否可能由于阻塞代码而错过事件?
  2. 如果是,与asyncio集成的这些功能的替代品是什么? 没有异步版本的PIL。
  3. 通常,异步中什么被视为“阻止代码”? 除了明显的操作,例如套接字,读取文件等。
    例如, os.path.join()是否被认为还可以? 如何处理一个numpy数组?

如果使用这些阻止呼叫,我的Web服务器会冻结吗? 更准确地说,事件循环是否可能由于阻塞代码而错过事件?

服务器将精确冻结执行图像功能的时间。 您不会错过任何事件,但是在执行图像功能时,所有事件处理都会延迟。

冻结事件循环是一种糟糕的情况-您应该避免这种情况。

如果是,与asyncio集成的这些功能的替代品是什么? 没有异步版本的PIL。

避免冻结事件循环的最简单,通用的方法-使用asyncio.run_in_executor在另一个线程或另一个进程中执行阻止功能。 那里的代码段显示了如何执行此操作,并在何时使用进程或线程提供了很好的解释:

def blocking_io():
    # File operations (such as logging) can block the
    # event loop: run them in a thread pool.
    with open('/dev/urandom', 'rb') as f:
        return f.read(100)

def cpu_bound():
    # CPU-bound operations will block the event loop:
    # in general it is preferable to run them in a
    # process pool.
    return sum(i * i for i in range(10 ** 7))

我只想补充一点,对于每个受CPU约束的操作,进程池可能并不总是一个好的解决方案。 如果图像功能不需要花费很多时间(特别是如果服务器没有多个处理器内核),则在线程中运行它们可能仍然会更有效率。

通常,异步中什么被视为“阻止代码”? 除了套接字,读取文件等明显的操作之外,例如,os.path.join()是否还可以吗? 如何处理一个numpy数组?

粗略地说,任何函数都在阻塞:它会在一段时间内阻塞事件循环。 但是像os.path.join这样的许多函数只花费很少的时间,所以它们不是问题,我们不称它们为“阻塞”。

当执行时间(和事件循环冻结)成为问题时,很难说确切的限制,尤其是考虑到此时间对于不同的硬件将有所不同。 我的偏见建议-如果您的代码在将控制权返回事件循环之前花了50毫秒(或可能要花50毫秒以上),请考虑将其阻塞并使用run_in_executor

UPD:

谢谢,使用一个(主线程的)事件循环并使用另一个将使用相同的循环添加任务的线程有意义吗?

我不确定您在这里的意思,但我认为不是。 我们需要另一个线程来运行一些作业,而不是在其中添加任务。

我需要某种方式让线程在图像处理完成后通知主线程。

只需等待run_in_executor结果或使用它启动任务即可。 run_in_executor是一个协程,它在后台线程中执行某些操作而不会阻塞事件循环。

它看起来像这样:

thrad_pool = ThreadPoolExecutor()


def process_image(img):
    # all stuff to process image here
    img.save()
    img.resize()


async def async_image_process(img):
    await loop.run_in_executor(
        thread_pool, 
        partial(process_image, img)
    )


async def handler(request):

    asyncio.create_task(
        async_image_process(img)
    )
    # we use task to return response immediately,
    # read https://stackoverflow.com/a/37345564/1113207

    return web.Response(text="Image processed without blocking other requests")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM