6

So the threading module has a Timer class inhereted from Thread class to repeatedly execute some tasks.

I was wondering why doesn't the multiprocessing module have something like an analogous TimedProcess class for e.g., which is inhereted from Process to repeatedly execute some tasks?

It is possible to write such a timed process and I have written one but still curious. Or am I missing something?

dano
  • 91,354
  • 19
  • 222
  • 219
Manas
  • 399
  • 1
  • 4
  • 13
  • https://docs.python.org/2/library/sched.html – Robert Harvey Aug 13 '14 at 23:07
  • See also http://stackoverflow.com/q/12435211 – Robert Harvey Aug 13 '14 at 23:08
  • As far as I can tell scheduler does not inheret from Process. If Timer can inheret from Thread, why can't another Timer say TimerProc inheret from Process? – Manas Aug 13 '14 at 23:14
  • @Manas: You wouldn't call it `TimerProc`, it'd just be `multiprocessing.Timer`. In fact, I believe you could copy and paste the code out of `threading.py`, change `Thread` to `Process` the two places it appears, and be done. – abarnert Aug 13 '14 at 23:32

2 Answers2

10

It's pretty straightforward to implement yourself:

from multiprocessing import Process, Event


class Timer(Process):
    def __init__(self, interval, function, args=[], kwargs={}):
        super(Timer, self).__init__()
        self.interval = interval
        self.function = function
        self.args = args
        self.kwargs = kwargs
        self.finished = Event()

    def cancel(self):
        """Stop the timer if it hasn't finished yet"""
        self.finished.set()

    def run(self):
        self.finished.wait(self.interval)
        if not self.finished.is_set():
            self.function(*self.args, **self.kwargs)
        self.finished.set()

I'm not sure why there isn't one included in the stdlib. Perhaps because its less likely to be useful?

dano
  • 91,354
  • 19
  • 222
  • 219
  • Yeah, I kind of ended up doing the same thing. But same hold true for Thread and Timer. So the decision to not include in stdlib is funny unless there is some pressing reason. As far as I can see, repeatedly executing a process offers more advantages than repeatedly executing threads. All the advantages of processes over threads like no shared memory, GIL, true multiprocessing hold. I can see uses for those features. – Manas Aug 13 '14 at 23:22
  • The question already says "It is possible to write such a timed process and I have written one", so I don't think showing how to write one answers the question. – abarnert Aug 13 '14 at 23:33
  • @abarnert Agreed - I've spent the last 15 minutes or so searching the mailing lists / commit logs for some evidence of *why* it wasn't included, so I could edit it into my answer. But as it appears you've found, there really isn't any mention of it. Seems to just be a case of "no one really cared enough to do it". – dano Aug 13 '14 at 23:40
  • @Manas It's quite possible that if you submitted a patch to add a `multiprocessing.Timer`, it would be accepted. The lack of results when you google "multiprocessing.timer", "multprocessing timer", etc. seems to suggest very few people have been missing it, though. – dano Aug 13 '14 at 23:46
  • People probably don't miss it because it is a trivial thing to implement, although I belive most just end up using `threading.Timer` which I belive is a bad way to repeatedly do tasks. – Manas Aug 13 '14 at 23:56
  • @Manas: I agree, `Timer` is really only good for single-threaded apps that need to tack on a single one-shot asynchronous callback, like "`SIGINT` the main thread in 30 seconds if not canceled". For anything else, you're going to need at least one thing it doesn't do—multiple timers that share a thread, recurring timers (that don't teardown and create a thread each recurrence), higher-resolution timers, timers that push notifications onto a work queue, … But `Timer` still makes great example code to build those on. – abarnert Aug 14 '14 at 18:08
5

This is a pretty open-ended question, and the literal answer wouldn't be very useful.

But let's try to come up with some educated guesses.

pyprocessing* didn't have it. Why not? Probably because it's not particularly useful.

Almost any non-trivial app that needs timers needs multiple timers, recurring timers, relatively fast timers, etc. Firing off a new thread for each timed event is a terrible idea.

So, why is it even in threading?

Well, for trivial apps, it can actually be useful. It's not that unreasonable to add threading to a single-process app just so you can kick off a Timer to signal the main thread and interrupt it if it gets lost, for example. But that's not relevant to multiprocessing.

Also, threading is one of those modules that's designed to be useful as example code, not just as a library—and that was especially true when it was first added. That's why the docs link to the source. And Timer is a great piece of sample code—it's obvious to what it does and how it works, and it's hard to think of anything much simpler that could demonstrate how to use a synchronization object. But you don't need the code in two places to serve as an example, and there's nothing additional and multiprocessing-specific to demonstrate.

And finally Itamar Shtull-Trauring wanted it, did the work, and offered it, and nobody had any good argument against including it; presumably the same thing never happened with pyprocessing.**

During the 2.6/3.0 planning, PEP 371 adapted pyprocessing into the stdlib multiprocessing module. This was a pretty big job, and done in a bit of a rush, especially since they took on the task of PEP8-ifying the names in threading so they wouldn't have to rename all of pyprocessing to match the non-standard names in threading just for someone to rename them all again when threading got fixed a year or two later. So, even though being a drop-in replacement for threading whenever possible was one of the secondary goals, I'm guessing nobody did a complete survey to make sure that was accomplished.

Since then, presumably, either nobody has noticed it was missing and suggested it, or nobody has made a compelling enough argument, or nobody did the actual work. If you believe it should be added, and can defend your belief, create a bug or write to python-ideas, and include your implementation, and sign a PSF contributor's agreement, and it may get you immortalized. :)

* Unfortunately, I can't find any good historical links to pyprocessing. The source repo is dead, the contributors moved on to maintaining the stdlib multiprocessing module and the PyPI multiprocessing backport, even that project has largely been supplanted by billiard, and in the intervening years a new and unrelated project has taken over the original name…

** Note that in issue #428326, where Timer was first suggested, more than half of the rationale is that it's good example code.

abarnert
  • 354,177
  • 51
  • 601
  • 671