'The task_in_progress_counter is needed because we want to know if the
consumer is processing something and let it finish. It is mainly used
in the has_pending_work().
For example:
* You can have pending work if there are items in the input_queue
* You can have pending work if there are still items to be read from
the output_queue by one of the consumers that reads our output.
* You can have pending work when there are no items in input_queue
and no items in output_queue but the threadpool inside the consumer
is processing something. This situation is handled by the
self._tasks_in_progress attribute and the _add_task and
_task_done methods.
So, for each _add_task() there has to be a _task_done() even if the
task ends in an error or exception.
Recommendation: Do NOT set the callback for apply_async to call
_task_done, the Python2.7 pool implementation won\'t call it if the
function raised an exception and you\'ll end up with tasks in progress
that finished with an exception.'

def _task_done(self, function_id):

    try:
        self._tasks_in_progress.pop(function_id)
    except KeyError:
        raise AssertionError(('The    function    %s    was    not    found!' % function_id))
