7
votes

Twisted: Pourquoi le passage d'un rappel différé à un fil différé rend le fil bloquant tout d'un coup?

J'ai essayé sans succès d'utiliser TXredis (l'API torsadée non bloquante pour ReDIS) pour une file d'attente de message persistante, j'essaie de créer un projet Scrapy que je travaille. J'ai constaté que bien que le client ne bloquait pas, il a été devenu beaucoup plus lent qu'il aurait pu être dû au fait que ce qui aurait dû être un événement dans la boucle de réacteur a été divisé en milliers d'étapes.

Afin, j'ai essayé de faire usage de Redis -py (l'API torsadée de blocage régulière) et enveloppant l'appel dans un fil différé. Cela fonctionne très bien, mais je souhaite effectuer un appellé à l'intérieur lorsque je voudrais faire un appel à Redis, car je voudrais configurer la mise en commun de la connexion dans les tentatives pour accélérer plus loin. p>

ci-dessous est mon interprétation de certains échantillons de code prélevé dans les documents tordus pour un fil différé pour illustrer mon étui d'utilisation: p> xxx pré>

et voici ma modification Pour la mise en commun de la connexion qui rend le code dans le blocage de fil différé: P>

#!/usr/bin/env python
from twisted.internet import reactor,defer
from twisted.internet.task import LoopingCall
import time

def main_loop():
    print 'doing stuff in main loop.. do not block me!'

def aBlockingRedisCall(x):
    if x<5: #all connections are busy, try later
        print '%s is less than 5, get a redis client later' % x
        x+=1
        d = defer.Deferred()
        d.addCallback(aBlockingRedisCall)
        reactor.callLater(1.0,d.callback,x)
        return d

    else: 
        print 'got a redis client; doing lookup.. this may take a while'
        time.sleep(10) # this is now blocking.. any ideas?
        d = defer.Deferred()
        d.addCallback(gotFinalResult)
        d.callback(x)
        return d

def gotFinalResult(x):
    return 'final result is %s' % x

def result(res):
    print res

def aBlockingMethod():
    print 'going to sleep...'
    time.sleep(10)
    print 'woke up'

def main():
    lc = LoopingCall(main_loop)
    lc.start(2)


    d = defer.Deferred()
    d.addCallback(aBlockingRedisCall)
    d.addCallback(result)
    reactor.callInThread(d.callback, 1)
    reactor.run()

if __name__=='__main__':
    main()


0 commentaires

3 Réponses :


12
votes

Eh bien, comme le Docs tordus Dites:

Les différés ne font pas le code magiquement pas bloquer p> blockQuote>

Chaque fois que vous utilisez le code de blocage, tel que SLEEP CODE>, vous devez le différer à un nouveau fil. p>

#!/usr/bin/env python
from twisted.internet import reactor,defer, threads
from twisted.internet.task import LoopingCall
import time

def main_loop():
    print 'doing stuff in main loop.. do not block me!'

def aBlockingRedisCall(x):
    if x<5: #all connections are busy, try later
        print '%s is less than 5, get a redis client later' % x
        x+=1
        d = defer.Deferred()
        d.addCallback(aBlockingRedisCall)
        reactor.callLater(1.0,d.callback,x)
        return d

    else: 
        print 'got a redis client; doing lookup.. this may take a while'
        def getstuff( x ):
            time.sleep(3)
            return "stuff is %s" % x

        # getstuff is blocking, so you need to push it to a new thread
        d = threads.deferToThread(getstuff, x)
        d.addCallback(gotFinalResult)
        return d

def gotFinalResult(x):
    return 'final result is %s' % x

def result(res):
    print res

def aBlockingMethod():
    print 'going to sleep...'
    time.sleep(10)
    print 'woke up'

def main():
    lc = LoopingCall(main_loop)
    lc.start(2)


    d = defer.Deferred()
    d.addCallback(aBlockingRedisCall)
    d.addCallback(result)
    reactor.callInThread(d.callback, 1)
    reactor.run()

if __name__=='__main__':
    main()


0 commentaires

0
votes

sur une note connexe, vous pouvez probablement gagner beaucoup à l'aide d'un client REDIS créé spécifiquement pour torsadé, tel que celui-ci: http://github.com/deldotdr/txredis


0 commentaires

3
votes

Il existe également un client ReDIS à jour à jour pour torsadé qui prend déjà en charge le nouveau protocole et les nouveaux fonctionnalités de Redis 2.x. Vous devriez définitivement essayer d'essayer. Ça s'appelle Txredisapi.

Pour la file d'attente de messages persistants, je recommanderais RestMQ. Un système de file d'attente de messages basé sur REDIS construit sur le cyclone et TXreDisapi.

http://github.com/gleicon/restmq

acclamations


0 commentaires