【问题标题】:Does a loop.run_in_executor functions need asyncio.lock() or threading.Lock()?loop.run_in_executor 函数是否需要 asyncio.lock() 或 threading.Lock()?
【发布时间】:2021-01-18 03:18:01
【问题描述】:

我为我的项目复制了以下代码,它对我来说效果很好,但我真的不明白以下代码如何运行我的blocking_function:

@client.event
async def on_message(message):  
      loop = asyncio.get_event_loop()
      block_response = await loop.run_in_executor(ThreadPoolExecutor(), blocking_function)

每次收到消息时都会调用 on_message。如果我收到多条消息,它们将被异步处理。

blocking_function 是一个同步函数,我不想在另一个blocking_function 运行时运行它。那么在blocking_function 中,我应该使用threading.Lock() 还是asyncio.lock()?

【问题讨论】:

  • 如果blocking_function没有用async def定义,你不能在其中使用asyncawait,所以你必须使用threading.Lock

标签: python-3.x multithreading asynchronous parallel-processing python-asyncio


【解决方案1】:

正如 dirn 在评论中指出的那样,在 blocking_function 中,您不能使用 asyncio.Lock,因为它不是异步的。 (相反的情况也适用:您不能从异步函数中锁定 threading.Lock,因为尝试这样做会阻塞事件循环。)如果您需要保护 blocking_function 的其他实例访问的数据,您应该使用 @987654325 @。

但我不太明白以下代码如何运行我的blocking_function

它将blocking_function 交给您创建的线程池来运行它。线程池排队并运行函数(从您的角度来看,这发生在“后台”),run_in_executor 安排事件循环在函数完成时得到通知,将其返回值作为 @ 的结果传递987654329@表达式。

请注意,您应该使用None 作为run_in_executor 的第一个参数。如果您使用ThreadPoolExecutor(),您将为每条消息创建一个全新的线程池,并且您永远不会丢弃它。线程池通常意味着创建一次,并为后续工作重用固定数量(“池”)的线程。 None 告诉 asyncio 使用它为此目的创建的线程池。

【讨论】:

    【解决方案2】:

    通过确保使用单个线程,您似乎可以轻松实现您想要的目标。

    一个简单的解决方案是确保对blocking_function 的所有调用都在单个线程上运行。这可以通过在 async 函数之外创建一个带有 1 个工作人员的 ThreadPoolExecutor 对象来轻松实现。然后对阻塞函数的每个后续调用都将在该单个线程上运行

    thread_pool = ThreadPoolExecutor(max_workers=1)
    @client.event
    async def on_message(message):  
          loop = asyncio.get_event_loop()
          block_response = await loop.run_in_executor(thread_pool, blocking_function)
    

    之后别忘了关闭线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-03
      • 1970-01-01
      • 2019-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-20
      相关资源
      最近更新 更多