class_docstr: Concurrent event loop context.
  
  Args:
      concurrency: max processing concurrency.
code: def __init__(self, concurrency: int):
      self._concurrency = concurrency
      self._sem = BoundedSemaphore(concurrency)
      self._loop = asyncio.new_event_loop()
      self._runner_t = Thread(target=self._run_loop)
      self._runner_t.daemon = True
  
      def cleanup():
          for _ in range(self._concurrency):
              self._sem.acquire()
          for _ in range(self._concurrency):
              self._sem.release()
          if self._runner_t.is_alive():
              self._loop.stop()
              self._runner_t.join(timeout=1)
              logging.debug(f"{self}: Closed `ConcurrentEventLoop`")
  
      atexit.register(cleanup)
  
file_path: pytorch_geometric/torch_geometric/distributed/event_loop.py
imports: import asyncio
  import atexit
  import logging
  from threading import BoundedSemaphore, Thread
  from typing import Callable, Optional
  import torch
label_desc: Use image node_id 1 to create a new ConcurrentEventLoop object  with example: obj = ConcurrentEventLoop(concurrency)