Плохая новость - готового решения сформулированной в вопросе задачи, похоже, нет. Нужно использовать брокеры или что-то подобное.
Хорошая новость - я снова попался на проблему XY. Всё нормально, если спрятать тяжёлые импорты в теле основной программы вот так:
# ------------------- main.py -------------------
async def main():
import urllib3 # как бы тяжелый модуль, нужный только главному скрипту
import importlib
... # получаем исходные данные
# динамически подтаскиваем нужный модуль
mod = importlib.import_module('modules.submodule')
m = mod.Module(x=-1) # используем класс из него
# этот метод под капотом использует мультипроцессинг
results = await m.run_tasks(some_data)
... # что-то делаем с результатами
if __name__ == '__main__':
import asyncio
asyncio.run(main())
# ------------------- modules/submodule.py -------------------
import asyncio
import concurrent.futures
import time
import sys
import os
class Module:
def __init__(self, x):
self.x = x
def __repr__(self) -> str:
return f'{self.__class__.__name__}(x={self.x!r}) {hex(id(self)).upper()} @ {os.getpid()}'
async def run_tasks(self, data):
self.x = len(items)
print(f'Using instance {self!r}')
loop = asyncio.get_running_loop()
pool = concurrent.futures.ProcessPoolExecutor(4) # где будем исполнять таск
# готовим таски к исполнению
futures = [loop.run_in_executor(pool, self.worker_func, item) for item in data]
# ждём их завершения
return await asyncio.gather(*futures, return_exceptions=True)
def worker_func(self, item):
# инстансы разные, разумеется, но их состояние, похоже, клонируется в новые процессы...
print(f'Using instance {self!r}. urllib3', 'is' if 'urllib3' in sys.modules else 'is not', 'present', flush=True)
time.sleep(0.1) # имитируем напряжённую работу
return repr(item)