import _xxsubinterpreters import os import threading import time class InterpreterThread(threading.Thread): def __init__(self, code): super().__init__() self._interp = _xxsubinterpreters.create() self._code = code def run(self): _xxsubinterpreters.run_string(self._interp, self._code) _xxsubinterpreters.destroy(self._interp) class ExecThread(threading.Thread): def __init__(self, code): super().__init__() self._code = code def run(self): exec(self._code) CODE = "import time; time.sleep(1)" CODE = "import math; math.factorial(100_000)" CODE = """ n = 50_000 fact = 1 for i in range(1, n + 1): fact = fact * i """ CPUS = os.cpu_count() def run_threads(worker): jobs = [worker(CODE) for _ in range(CPUS)] t1 = time.perf_counter() for job in jobs: job.start() for job in jobs: job.join() t2 = time.perf_counter() return t2 - t1 def bench_sequential(): t1 = time.perf_counter() for _ in range(CPUS): exec(CODE) t2 = time.perf_counter() return t2 - t1 def bench_threads(): return run_threads(ExecThread) def bench_subinterpreters(): return run_threads(InterpreterThread) for bench, func in ( ("Sequential", bench_sequential), ("Threads", bench_threads), ("Subinterpreters", bench_subinterpreters), ): dt = func() print(f"{bench}: {dt:.1f} sec (CPUS={CPUS})")