from multiprocessing import Process, connection, current_process, Manager
from multiprocessing.managers import BaseManager
from random import randint
from time import sleep
from datetime import datetime

class myc(object):
    def __init__(self, num):
        self.num = num
        self.err = 0
    def __str__(self):
        return "num:" + str(self.num) + " err: " + str(self.err)
    def error(self):
        self.err += 1
    def prme(self):
        return "err: " + str(self.err)

def run(cld):
    x = randint(2,10)
    sleep(x/2)
    for obj in cld:
        for i in range(x): obj.error()
    #print(f"{datetime.now()} {current_process().name} exiting")
    print(current_process().name, "increased by", x)
    for i in cld:
        print(current_process().name, ":", i.prme())

class CustomManager(BaseManager):
    pass


if __name__ == '__main__':
    todo = 10
    CustomManager.register('myc', myc)
    manager = CustomManager()
    manager.start()
    sharedlist = [manager.myc(a) for a in range(20)]
    maxim = 3
    done = 0
    pool = {}
    cool = 0
    while len(pool) < maxim and todo > 0:
        while len(pool) < maxim:
            print("Starting process...", str(len(pool)+1))
            proc = Process(target=run, args=(sharedlist[cool:cool+2],))
            proc.start()
            todo -= 1
            pool[proc.sentinel] = proc
        print("Pool has", len(pool), "processes, todo is", todo, "entering wait")
        cool += 2
        ready = connection.wait(pool[p].sentinel for p in pool)
        done += len(ready)
        for finished in ready:
            del pool[finished]
        print(f"{datetime.now()} {current_process().name} unblocked")
    print("waiting for the rest", len(pool))
    for proc in pool:
        pool[proc].join()
        pool[proc].close()
    print("list length is", len(sharedlist))
    for i in sharedlist:
        print(current_process().name, ":", i.prme())

