map()

Step 4: map()

A common pattern is "run this function over all these inputs and give me the results in order." Add a map convenience that submits one job per item, runs them, and returns the results as a list, in the same order as the inputs.

  • map(fn, iterable): submit fn(item) for each item, run the pool, return [future.result() for ...] in input order

Because you collect the futures in order, the results line up with the inputs even though the pool ran them as a batch.

Hints
Starter code
from collections import deque


class Future:
    def __init__(self):
        self._done = False
        self._result = None
        self._exc = None

    def set_result(self, value):
        self._result = value
        self._done = True

    def set_exception(self, exc):
        self._exc = exc
        self._done = True

    def done(self):
        return self._done

    def result(self):
        if not self._done:
            raise RuntimeError("future is not done")
        if self._exc is not None:
            raise self._exc
        return self._result


class ThreadPool:
    def __init__(self, num_workers):
        self.num_workers = num_workers
        self._queue = deque()

    def submit(self, fn, *args, **kwargs):
        fut = Future()
        self._queue.append((fut, fn, args, kwargs))
        return fut

    def run(self):
        while self._queue:
            fut, fn, args, kwargs = self._queue.popleft()
            try:
                fut.set_result(fn(*args, **kwargs))
            except Exception as e:
                fut.set_exception(e)

    def map(self, fn, iterable):
        """Submit fn over each item, run, and return results in input order."""
        # TODO: submit fn against each item in turn, holding on to the futures in
        #   the order you created them, then drain the pool once and read every
        #   future's result into a list that lines up with the inputs. A job that
        #   blew up surfaces its exception at the moment its result is read.
        pass
Write it on a laptop

The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.