import logging import multiprocessing import multiprocessing as mp import threading from concurrent.futures import ThreadPoolExecutor from logging import Logger from socket import socket from server.RequestHandler import RequestHandler THREAD_LIMIT = 20 def worker(address, name, log_level, queue: mp.Queue, stop_event: mp.Event): logging.basicConfig(level=log_level) logger = multiprocessing.log_to_stderr(level=log_level) runner = Worker(address, name, logger, queue, stop_event) runner.logger.debug("Worker %s started", name) try: runner.run() except KeyboardInterrupt: logger.debug("Ctrl+C pressed, terminating") runner.shutdown() class Worker: host: str name: str logger: Logger queue: mp.Queue executor: ThreadPoolExecutor stop_event: mp.Event finished_queue: mp.Queue def __init__(self, host, name, logger, queue: mp.Queue, stop_event: mp.Event): self.host = host self.name = name self.logger = logger self.queue = queue self.executor = ThreadPoolExecutor(THREAD_LIMIT) self.stop_event = stop_event self.finished_queue = mp.Queue() for i in range(THREAD_LIMIT): self.finished_queue.put(i) def run(self): while not self.stop_event.is_set(): # Blocks until thread is free self.finished_queue.get() # Blocks until new client connects conn, addr = self.queue.get() if conn is None or addr is None: break self.logger.debug("Received new client: %s", addr) # submit client to thread print(threading.get_ident()) self.executor.submit(self._handle_client, conn, addr) self.shutdown() def _handle_client(self, conn: socket, addr): try: self.logger.debug("Handling client: %s", addr) handler = RequestHandler(conn, self.logger, self.host) handler.listen() except Exception as e: self.logger.debug("Internal error", exc_info=e) # Finished, put back into queue self.finished_queue.put(threading.get_ident()) def shutdown(self): self.logger.info("shutting down") self.executor.shutdown()