ThreadPoolExecutor - callback guaranteed to run in same thread as the submitted function?
Ian Kelly
ian.g.kelly at gmail.com
Thu Sep 25 11:40:34 EDT 2014
On Thu, Sep 25, 2014 at 8:47 AM, Marko Rauhamaa <marko at pacujo.net> wrote:
> Ian Kelly <ian.g.kelly at gmail.com>:
>
>> On Thu, Sep 25, 2014 at 3:46 AM, Marko Rauhamaa <marko at pacujo.net> wrote:
>>> Example (pseudocode):
>>>
>>> def callback(self):
>>> with self.lock:
>>> ...
>>>
>>> def xyz(self, f):
>>> with self.lock:
>>> ...
>>> f.add_done_callback(self.callback)
>>>
>>> The code will deadlock if the callback is invoked immediately.
>>
>> Easily solved using a re-entrant lock.
>
> Not easily. Your state transition might not be complete at the time of
> the preemption. Many such issues can be resolved by moving the
> preemptive function calls to the end of the critical section, but that
> is not always possible, easy or taken into account.
Fair enough. In the simple example above, I see no harm in simply
moving the add_done_callback call outside (after) the "with self.lock"
block altogether. I can imagine more complex examples where the call
is further down the stack and harder to isolate from the lock,
although I would argue that's probably a code smell.
> If preemption needs to be prepared for, the real solution is:
>
>
> def xyz(self, f):
> with self.lock:
> ...
> def add_callback():
> f.add_done_callback(self.callback)
> self.executor.schedule(add_callback)
>
> which is ugly, of course.
YMMV, but I think I would prefer to make the executor.schedule call be
the callback:
def callback(self, f):
with self.lock:
...
def xyz(self, f):
with self.lock:
...
f.add_done_callback(
functools.partial(self.executor.schedule, self.callback))
More information about the Python-list
mailing list