2011-04-18 30 views
6
 
from twisted.internet import reactor 
from twisted.internet import threads 
from twisted.internet import defer 
import time 

def worker(arg): 
    print 'Hello world' 
    time.sleep(10) 
    return 1 

def run(): 
    print 'Starting workers' 
    l = [] 
    for x in range(2): 
     l.append(threads.deferToThread(worker, x)) 
    return defer.DeferredList(l) 

def res(results): 
    print results 
    reactor.stop() 

d = run() 
d.addCallback(res) 
reactor.run() 

İşçiler zaman aşımıyla nasıl durdurulur?Nasıl zaman aşımına uğramış erteleme zaman aşımı eklenir

cevap

5

Sizinle işbirliği yapmadıkça dişler kesilemez. time.sleep(10) işbirliği yapmayacak, bu yüzden bu işçiyi kesebileceğinizi düşünmüyorum. Bu da, belirli Twisted değildir

def worker(stop, jobs): 
    for j in jobs: 
     if stop: 
      break 
     j.do() 

stop = [] 
d = deferToThread(worker) 

# This will make the list eval to true and break out of the loop. 
stop.append(None) 

: Birkaç ayrık aşaması vardır, ya da bazı görevler üzerinde bir döngü içinde faaliyet işçinin başka tür varsa, o zaman böyle bir şey yapabilirsiniz. Bu, iş parçacığının Python'da nasıl işlediği.

3

İpliklerin kesilmesi mümkün olmamakla birlikte, Ertelenmiş 10.1.0 ve sonraki sürümlerde kullanılabildiğini düşündüğüm cancel işlevi ile ertelenebilir.

Deferred belirli bir süre sonra tetiklenmemişse belirli bir işlevi geri çağırmak için Deferreds yapmak için aşağıdaki sınıfı kullandım. OP'nin konusuyla aynı soruyu taşıyan bir kişi için yararlı olabilir.

DÜZENLEME: Aşağıdaki yorumların önerdiği gibi, defer.Deferred'dan miras almamak en iyisidir. Bu nedenle, aynı efekti elde eden bir sarıcı kullanmak için kodu değiştirdim. Zaman aşımından önce

class DeferredWrapperWithTimeout(object): 
    ''' 
    Holds a deferred that allows a specified function to be called-back 
    if the deferred does not fire before some specified timeout. 
    ''' 
    def __init__(self, canceller=None): 
     self._def = defer.Deferred(canceller) 

    def _finish(self, r, t): 
     ''' 
     Function to be called (internally) after the Deferred 
     has fired, in order to cancel the timeout. 
     ''' 
     if ((t!=None) and (t.active())): 
      t.cancel() 
     return r 

    def getDeferred(self): 
     return self._def 

    def addTimeoutCallback(self, reactr, timeout, 
          callUponTimeout, *args, **kw): 
     ''' 
     The function 'callUponTimeout' (with optional args or keywords) 
     will be called after 'timeout' seconds, unless the Deferred fires. 
     ''' 

     def timeoutCallback(): 
      self._def.cancel() 
      callUponTimeout(*args, **kw) 
     toc = reactr.callLater(timeout, timeoutCallback) 
     return self._def.addCallback(self._finish, toc) 

Örnek geri arama: ve başka hiçbir "sözde"

from twisted.internet import reactor 

from DeferredWithTimeout import * 

dw = DeferredWrapperWithTimeout() 
d = dw.getDeferred() 

def testCallback(x=None): 
    print "called" 

def testTimeout(x=None): 
    print "timedout" 

d.addCallback(testCallback) 
dw.addTimeoutCallback(reactor, 20, testTimeout, "to") 
reactor.callLater(2, d.callback, "cb") 
reactor.run() 

Baskılar. callback'inde önce

Örnek zaman aşımı:

from twisted.internet import reactor 

from DeferredWithTimeout import * 

dw = DeferredWrapperWithTimeout() 
d = dw.getDeferred() 

def testCallback(x=None): 
    print "called" 

def testTimeout(x=None): 
    print "timedout" 

d.addCallback(testCallback) 
dw.addTimeoutCallback(reactor, 20, testTimeout, "to") 
reactor.run() 

Baskılar 20 saniye sonra "süresi sona erdi" ve başka bir şey.

+2

Gerçekten 'Deferred' alt sınıfını seçmemelisiniz. Bir alt sınıfı değil, bu işlevselliği ayrı bir yardımcı olarak uygulayın. http://pyvideo.org/video/1684/the-end-of-object-inheritance-the-beginning-of –

+0

Alt sınıfları değil, olağan uyarılara ek olarak, "Deferred" bir * özellikle * kötü bir şeydir alt sınıf, çünkü davranışı kendi uygulamasıyla ilgili çok özel şeyler üstlenir ve belirli yöntemlerin geçersiz kılınmasına iyi tepki vermez. – Glyph

+0

Bu videonun bağlantısı için teşekkürler! Kod tasarlama biçimimi tamamen değiştirdi. – Corey

0

Eh, cevabım parçacıkları ilgili değil ama söylendiği gibi, ayrı bir yardımcı olarak zaman aşımı işlevleri uygulayabilirsiniz:

from twisted.internet import defer 

def add_watchdog(deferred, timeout=0.05): 

    def callback(value): 
     if not watchdog.called: 
      watchdog.cancel() 
     return value 

    deferred.addBoth(callback) 

    from twisted.internet import reactor 
    watchdog = reactor.callLater(timeout, defer.timeout, deferred) 

d = defer.Deferred() 
add_watchdog(d) 

Sonra en ertelenmiş errback içinde tuzak defer.TimeoutError ihtiyacınız eğer.

+0

hmmm iptal ediliyor gibi görünüyor –

+0

@ CarlD'Halluin, detaylandırmaya özen gösterin veya bir düzenleme önerin? – TCAllen07

0

Bunu bir dekoratör kullanarak yaparız. Bu yöntem, zaman aşımına ulaşıldığında ertelenenin iptal edilmesi avantajına sahiptir. Bu, bir şekilde Twisted kütüphanesinin bir parçası haline gelmelidir imho

from twisted.internet import defer, reactor 

def timeout(secs): 
    """Decorator to add timeout to Deferred calls""" 
    def wrap(func): 
     @defer.inlineCallbacks 
     def _timeout(*args, **kwargs): 
      raw_d = func(*args, **kwargs) 
      if not isinstance(raw_d, defer.Deferred): 
       defer.returnValue(raw_d) 

      timeout_d = defer.Deferred() 
      times_up = reactor.callLater(secs, timeout_d.callback, None) 

      try: 
       raw_result, timeout_result = yield defer.DeferredList(
        [raw_d, timeout_d], fireOnOneCallback=True, fireOnOneErrback=True, 
        consumeErrors=True) 
      except defer.FirstError as e: # Only raw_d should raise an exception 
       assert e.index == 0 
       times_up.cancel() 
       e.subFailure.raiseException() 
      else: # timeout 
       if timeout_d.called: 
        raw_d.cancel() 
        raise Exception("%s secs have expired" % secs) 

      # no timeout 
      times_up.cancel() 
      defer.returnValue(raw_result) 
     return _timeout 
return wrap