tags:

views:

218

answers:

2

Dear everyone, I have the following server running:

class ThasherProtocol(basic.LineReceiver):
    def lineReceived(self, line):
        dic = simplejson.loads( line)
        ret = self.factory.d[ dic['method'] ]( dic['args'] )
        self.transport.write( simplejson.dumps( ret) )
        self.transport.loseConnection()



class ThasherFactory(ServerFactory):
    protocol = ThasherProtocol 

    def __init__(self):
        self.thasher = Thasher()
        self.d= {   
            'getHash': self.thasher.getHash,
            'sellHash' : self.thasher.sellHash
            }


reactor.listenUNIX( c.LOCATION_THASHER, ThasherFactory() )
reactor.run()

I have multiple files importing a special function called "getHash" from a particular file. Note that getHash's arguments are only gonna be a dictionary of texts (strings). How do I write a client function (getHash) that can be simply:

from particular file import getHash
i = getHash( { 'type':'url', 'url':'http://www.stackoverflow.com' } )

Note that ALL I WANT TO DO is: 1) dump a dict into json, 2) dump that json into the particular socket, 3) wait for that to come back and unpack the json

+2  A: 

You want getHash to return a Deferred, not a synchronous value.

The way to do this is to create a Deferred and associate it with the connection that performs a particular request.

The following is untested and probably won't work, but it should give you a rough idea:

import simplejson
from twisted.python.protocol import ClientFactory
from twisted.internet.defer import Deferred
from twisted.internet import reactor
from twisted.protocols.basic import LineReceiver

class BufferingJSONRequest(LineReceiver):
    buf = ''

    def connectionMade(self):
        self.sendLine(simplejson.dumps(self.factory.params))

    def dataReceived(self, data):
        self.buf += data

    def connectionLost(self, reason):
        deferred = self.factory.deferred
        try:
            result = simplejson.load(self.buf)
        except:
            deferred.errback()
        else:
            deferred.callback(result)

class BufferingRequestFactory(ClientFactory):
    protocol = BufferingJSONRequest

    def __init__(self, params, deferred):
        self.params = params
        self.deferred = deferred

    def clientConnectionFailed(self, connector, reason):
        self.deferred.errback(reason)

def getHash(params):
    result = Deferred()
    reactor.connectUNIX(LOCATION_THASHER,
                        BufferingRequestFactory(params, result))
    return result

Now, in order to use this function, you will already need to be familiar with Deferreds, and you will need to write a callback function to run when the result eventually arrives. But an explanation of those belongs on a separate question ;).

Glyph
Yes thank you. But if this takes less than a millionth of a second, is there really a need to return a Deferred? Wouldn't returning a deferred be just an overkill? Can I do this without a Deferred? ( Note that I am using this more than a few million times per try and I really have to cut down on the unnecessary parts. )
Actually I consulted with the folks at #twisted and the conclusion is they don't think twisted is really what I am looking for. I cannot run reactor.run on my client because reactor.run is blocking
Deferreds are not about things taking a *long* time, they're about taking a *variable* amount of time. If you need to make 1000 requests, most of them will take a very short time (although probably not quite as little as a millionth of a second; more like a few thousandths) but ten of them will take 25 seconds because of some weird network congestion issue you can't predict.If you sit there and wait for every request to come back, your program will be slow and freeze up all the time, even if "most of the time" the call is fast.
Glyph
More than the speed issue, there's the issue of what happens when you call 'reactor.run()'. In the best case it would cause your entire program to freeze, but if you have other stuff going on in the background, what should happen to it? Should it try to keep going on inside the inner call to "run" as well? It turns out that this can be the source of a lot of hugely surprising bugs, even if Twisted worked exactly how you would expect it to here.
Glyph
A: 

I managed to solve my own problem.

Use sockets (Unix sockets in particular) it speed up my app 4x and it's not difficult to use at all.

so now my solution is simplejson + socket

Sounds like twisted was too heavyweight for what you were trying to do.
Tom Leys