Class with multiple workers
Use multiprocessing.Pool
The multiprocessing library already has a worker pool implementation ready to be used. Your code could be rewritten as:
import time
from multiprocessing import Pool

def f(x):
    time.sleep(random.uniform(0.01, 0.5))
    return x * 12

if __name__ == &quot;__main__&quot;:
    c = Pool(2)

    for i in range(5):
        n = random.randint(1, 20)
        r = c.map_async(f, list(range(n)))
        print(f&quot;sent: {n}&quot;)
        print(f&quot;got: {len(r.get())}&quot;)

While multiprocessing.Pool allows you to check if the results are ready by using .ready() on the result of an apply_async() or map_async() call, you can't get a partial result from map_async(). However, if you do want to process individual results as soon as they are ready, you can consider calling apply_async() with a callback function that handles the result.