mirror of
https://github.com/bringout/oca-technical.git
synced 2026-04-18 10:32:00 +02:00
58 lines
1.8 KiB
Python
58 lines
1.8 KiB
Python
# Copyright 2025 ACSONE SA/NV
|
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/LGPL).
|
|
|
|
import asyncio
|
|
import queue
|
|
import threading
|
|
from contextlib import contextmanager
|
|
from typing import Generator
|
|
|
|
|
|
class EventLoopPool:
|
|
def __init__(self):
|
|
self.pool = queue.Queue[tuple[asyncio.AbstractEventLoop, threading.Thread]]()
|
|
|
|
def __get_event_loop_and_thread(
|
|
self,
|
|
) -> tuple[asyncio.AbstractEventLoop, threading.Thread]:
|
|
"""
|
|
Get an event loop from the pool. If no event loop is available, create a new one.
|
|
"""
|
|
try:
|
|
return self.pool.get_nowait()
|
|
except queue.Empty:
|
|
loop = asyncio.new_event_loop()
|
|
thread = threading.Thread(target=loop.run_forever, daemon=True)
|
|
thread.start()
|
|
return loop, thread
|
|
|
|
def __return_event_loop(
|
|
self, loop: asyncio.AbstractEventLoop, thread: threading.Thread
|
|
) -> None:
|
|
"""
|
|
Return an event loop to the pool for reuse.
|
|
"""
|
|
self.pool.put((loop, thread))
|
|
|
|
def shutdown(self):
|
|
"""
|
|
Shutdown all event loop threads in the pool.
|
|
"""
|
|
while not self.pool.empty():
|
|
loop, thread = self.pool.get_nowait()
|
|
loop.call_soon_threadsafe(loop.stop)
|
|
thread.join()
|
|
loop.close()
|
|
|
|
@contextmanager
|
|
def get_event_loop(self) -> Generator[asyncio.AbstractEventLoop, None, None]:
|
|
"""
|
|
Get an event loop from the pool. If no event loop is available, create a new one.
|
|
|
|
After the context manager exits, the event loop is returned to the pool for reuse.
|
|
"""
|
|
loop, thread = self.__get_event_loop_and_thread()
|
|
try:
|
|
yield loop
|
|
finally:
|
|
self.__return_event_loop(loop, thread)
|