[Tutor] Starbucks does not use two-phase commit

Bernard Lebel 3dbernard at gmail.com
Mon Jan 23 16:15:56 CET 2006


Hi Danny,

Just to report something regarding the code you have provided.

I noticed that when I do a keyboard interrupt, I get the keyboard
interrupt exception messages, but after that it keeps hangning and
never returns to the command line input mode. I have to close the
shell to really end the program afaics.

After reading Todd's emails, I wondered if it had something to do with
how the threaded queue is started.

In your example, you use:

Thread( target = <function name> ).start()


While I have been using the thread module, using:

thread.start_new( <function name>, ( <thread id>, <other args> ) )


When I implemented your example in my program, I also used your
approach, and started having the hanging behavior. I reconverted the
thread spawn to my own approch, just to see if it would make a
difference.

And with my approach, the keyboard interrupts really aborts the
program, the shell returns to command line input mode.


Any idea why those two methods of starting threads can behave so differently?


Thanks
Bernard



On 1/20/06, Bernard Lebel <3dbernard at gmail.com> wrote:
> Ultra-nice Danny, it works (ie: I have implemented your example in my
> code and it runs as it should).
>
> I have to admit that I'm a little bit puzzled by this chain of
> instantiation and argument passing, however I intend to decipher it
> properly.
>
>
> Thanks again!
> Bernard
>
>
>
>
> On 1/20/06, Danny Yoo <dyoo at hkn.eecs.berkeley.edu> wrote:
> >
> >
> > On Fri, 20 Jan 2006, Bernard Lebel wrote:
> >
> > > So have written a little test script. The fact is that I want to be able
> > > to manage the same queue from separate threads. Below is an example of
> > > what my real program is doing:
> >
> >
> > Hi Bernard,
> >
> > One problem is that there's a single outputQueue being presented to get
> > results back from the Server.
> >
> > A different approach is to use a lot of outputQueues.  *grin*
> >
> > The idea is that when we send a job submission, we immediately get back a
> > "ticket".  We can then use this ticket to claim() our result.  Each ticket
> > is unique to a job submission, so we shouldn't see any bleeding going on
> > between clients.
> >
> >
> > Here's some code that implements this idea.  It's a little complex, so you
> > may want to read through it slowly:
> >
> >
> > ################################################
> > from threading import Thread
> > from Queue import Queue
> >
> >
> > class Ticket:
> >     """A small token that we can use to claim our result."""
> >     def __init__(self, q):
> >         self.q = q
> >         self.result = None
> >         self.done = False
> >
> >     def claim(self):
> >         if not self.done:
> >             self.result = self.q.get()
> >             self.done = True
> >         return self.result
> >
> >
> > class Server:
> >     _QUIT_JOB = ['Quit!']
> >
> >     def __init__(self):
> >         """A queue will contain 2-tuples of (job, outputQueue)
> >         elements."""
> >         self.queue = Queue()
> >
> >
> >     def startServer(self):
> >         """Brings the server online."""
> >         Thread(target=self._jobLoop).start()
> >
> >
> >     def schedule(self, job):
> >         """Schedules a job to be done and returns a ticket that the
> >         client can use later to claim the result of the job."""
> >         outputQueue = Queue()
> >         self.queue.put((job, outputQueue))
> >         return Ticket(outputQueue)
> >
> >
> >     def scheduleShutdown(self):
> >         """Add a 'job' that shuts the system down."""
> >         self.queue.put((Server._QUIT_JOB, None))
> >
> >
> >     def _jobLoop(self):
> >         """Continue looping through tasks."""
> >         while True:
> >             print "Looping..."
> >             (nextJob, outputQueue) = self.queue.get()
> >             if nextJob is Server._QUIT_JOB:
> >                 return
> >             returnValue = self._doJob(nextJob)
> >             outputQueue.put(returnValue)
> >
> >
> >     def _doJob(self, job):
> >         print "I'm doing", job
> >         return job + job ## something to show that we're doing something
> >
> >
> >
> > def separateCaller(server):
> >     for i in range(1000, 1004 + 1):
> >         print "--Separate caller asks %d" % i
> >         ticket = server.schedule(str(i))
> >         print "--Separate caller got %s" % ticket.claim()
> >
> >
> > if __name__ == '__main__':
> >     server = Server()
> >     server.startServer()
> >     Thread(target=separateCaller, args=(server,)).start()
> >
> >     result1 = server.schedule("1")
> >     print "result1: %s" % result1.claim()
> >     result2 = server.schedule("2")
> >     print "result2: %s" % result2.claim()
> >     result3 = server.schedule("3")
> >     print "result3: %s" % result3.claim()
> >     server.scheduleShutdown()
> > #############################################################
> >
> >
> > Play around with this a bit and see if it makes sense to you.  You might
> > also be interested in the amusing article "Starbucks Does Not Use
> > Two-Phase Commit":
> >
> >     http://www.eaipatterns.com/ramblings/18_starbucks.html
> >
> > as it touches on concepts in the code.
> >
> >
> > If you have more questions, please feel free to ask!
> >
> >
>


More information about the Tutor mailing list