[Twisted-Python] Twisted Advice

Paul Wilson paulalexwilson at gmail.com
Thu Apr 17 07:04:13 EDT 2008


>  >
>  >I would like to provide an environment where developers can write call
>  >servicing applications with no knowledge of the network. I had rested
>  >on a coroutine approach, whereby a developer could write something
>  >like this:
>  >
>  >   response, events = (yield getKeyPress(SomePromptAnnouncement))
>  >
>
>  Just to clarify - this looks like a generator rather than a coroutine.
>
>  >With the response, the developer can do an undefined number of things,
>  >taking an undefined amount of time. During this time, management
>  >events can arrive on a separate port, to which the developer gets
>  >knowledge of through the yield statement.
>  >
>  >On the other side of this generator is a scheduler which takes
>  >instructions such as "getKeyPress" and passes it through twisted to
>  >the remote client, such that it can play the announcement and get a
>  >keypress. The scheduler gets the response and sends to back to the
>  >generator, along with any events that have arrived on this separate
>  >port.
>  >
>  >When a call/connection arrives, the client will send an opening
>  >line(s) to which I was specify the correct LineRecieved method. This
>  >will trigger some scheduler code defined elsewhere via a deferred,
>  >which will prompt the developer's code for some instructions, such as
>  >"PlayPrompt". Am I correct in thinking that while a developer's code
>  >is executing, all other connections are paused, and that the twisted
>  >server will not accept new connections until it returns?
>
>  Yes, that's correct.  Twisted is single-threaded - it invokes event
>  handlers in the same thread it uses to monitor event sources.  As long
>  as an event handler is running, event sources are not monitored for
>  events and no other handlers will be invoked.
>
>  >
>  >My original assumption was that Twisted would spawn a new thread
>  >within which the scheduler would be set to run to manage the
>  >communication for the duration of the customer call/interaction.
>  >However, the approach taken by twisted is that if the developer's code
>  >got itself in a muddle or infinite loop or took a very long time
>  >accessing a database, the rest of the application would just be
>  >frozen.
>
>  Generally speaking, Twisted will only create a thread when application
>  code asks it to.
>
>  >
>  >I wrote a quick test app that defers to a function that sleeps then
>  >returns its response line. During the 20 seconds that the test server
>  >took to return a line, the server would not accept any other requests
>  >until the sleep function ended.
>
>  The "defers to a function" language is a bit confusing.  However, your
>  conclusion sounds right.  If you block the reactor thread, nothing else
>  will happen.
>
>  >Clearly, I must be missing something; I have designed my application
>  >upon the wrong axis. If so, I have some misunderstanding as to how to
>  >properly structure an application like this upon Twisted. Or, twisted
>  >is a framework whereby the response to a network event is expect to
>  >arrive immediately.
>
>  It's not necessary for responses to arrive immediately.  Responses just
>  need to be obtained without blocking.  For example, if getting a response
>  involves talking to someone else over the network, then Twisted has some
>  networking APIs that don't block. ;)  Likewise, twisted.enterprise lets
>  you talk to a rdbm (it actually uses threads, but it mostly doesn't show
>  that to you).

>  >I have seen "deferToThread" mentioned but I cannot find enough
>  >documentation to decide whether it's what I need or not. Or perhaps
>  >callInThread() is what I need?
>
>  One of these may be appropriate.  You could decide that in your application
>  framework, user code is always run in a non-reactor thread.  This is easily
>  accomplished: your event handler just needs to invoke user code in a thread
>  instead of directly.  deferToThread lets you run a function in a thread and
>  gives you a Deferred which will be called back with the return value of the
>  function when it returns or which will errback if it raises an exception.
>  callInThread is lower level, not exposing the result of the function.

Ahh. Okay; thanks for this. deferToThread looks like a good option
here and seems to fit what I'm looking for. From experience, can you
point me towards some good code that uses deferToThread?

>  >
>  >Any suggestions about this would be very much appreciated. Even
>  >better, if anybody knows of good documentation/tutorials they can
>  >point me to, that would be appreciated also.
>
>  It sounds like you're looking for deferToThread or one of its friends.
>  Note however that just throwing user code into a thread doesn't mean
>  programmers can be oblivious to their environment.  It simply trades the
>  need to pay attention to when you block and for how long for the more
>  complex task of paying attention to thread safety.  If each task is
>  isolated from all others, this may be a good trade-off to make, but if
>  there's shared state it may not be.

Thanks for your reply; there are some subtle and difficult questions
to answer here. I'd like each instance of the developer's code to be
isolated with it's own state using threading.local, but ultimately
I'll use deferToThread to set it all up.

I assume that I can use some threadsafe implementation (if the GIL
doesn't enforce that anyway) of a dictionary to store the global
information between each call handling thread.

Thanks again for your time.

>  Jean-Paul




More information about the Twisted-Python mailing list