2017-02-25 4 views
1

Ich habe ein paar Twitter Schaber in Python geschrieben und schreibe ein anderes Skript, um sie aufrechtzuerhalten, selbst wenn sie eine Auszeit, Trennung leiden usw.Python-Modul Funktion sofort in Thread Rückkehr

Meine aktuelle Lösung ist wie folgt:

Jede Schaber Datei hat eine doScrape/1 Funktion darin, die einen Schaber starten und es einmal ausgeführt, zB:

def doScrape(logger): 
    try: 
     with DBWriter(logger=logger) as db: 
      logger.log_info("starting", __name__) 
      s = PastScraper(db.getKeywords(), TwitterAuth(), db, logger) 
      s.run() 
    finally: 
     logger.log_info("Done", __name__) 

Wo läuft eine nahezu unendliche Schleife ist, die gewonnen 't brechen, es sei denn, es gibt eine Ausnahme.

Um eine von jeder Art von Schaber auf einmal zu laufen, ich bin mit diesem Code (mit ein paar zusätzlichen Importe):

from threading import Thread 

class ScraperThread(Thread): 
    def __init__(self, module, logger): 
     super(ScraperThread, self).__init__() 
     self.module = module # Module should contain a doScrape(logger) function 
     self.logger = logger 


    def run(self): 
     while True: 
      try: 
       print "Starting!" 
       print self.module.doScrape 
       self.module.doScrape(self.logger) 
      except: # if for any reason we get disconnected, reconnect 
       self.logger.log_debug("Restarting scraper", __name__) 

if __name__ == "__main__": 
    with Logger(level="all", handle=open(sys.argv[1], "a")) as l: 
     past = ScraperThread(PastScraper, l) 
     stream = ScraperThread(StreamScraper, l) 
     past.start() 
     stream.start() 
     past.join() 
     stream.join() 

Allerdings scheint es, dass mein Aufruf von doScrape von oben Rückkehr sofort, daher "Start!" wiederholt wird in der Konsole ausgegeben, und die „Fertig“ -Meldung im finally-Block nicht in das Protokoll geschrieben, während, wenn sie einzeln wie so läuft:

if __name__ == "__main__": 
    # Example instantiation 
    from Scrapers.Logging import Logger 
    with Logger(level="all", handle=open(sys.argv[1], "a")) as l: 
     doScrape(l) 

Der Code läuft immer, wie erwartet. Ich bin ein bisschen ratlos.

Gibt es etwas albern, dass ich vielleicht verpasst haben?

+0

So funktioniert es, wenn Sie 'doScrape' nennen, aber nicht, wenn Sie rufen' PastScraper.doScrape' oder 'StreamScraper.doScrape'? –

Antwort

0

Aha, löste es! Es war tatsächlich, dass ich nicht erkannte, dass ein Standardargument (hier in TwitterAuth()) zur Definitionszeit ausgewertet wird. TwitterAuth liest die API-Schlüsseleinstellungen aus einem Dateihandle und das Standardargument öffnet die Standardkonfigurationsdatei. Da dieses Datei-Handle zur Definitionszeit erzeugt wird, hatten beide Threads den gleichen Handle, und nachdem sie es gelesen hatten, versuchte der andere, am Ende der Datei zu lesen und eine Ausnahme auszulösen. Dies wird behoben, indem die Datei vor der Verwendung zurückgesetzt und ein Mutex verwendet wird.

Beifall bis Irmen de Jong für mich in der richtigen Richtung.

1

erhalten die Windel Muster in Ihrer Methode run() los zu werden, wie in: diese Catch-allen Exception-Handler loszuwerden. Sie werden wahrscheinlich den Fehler dann dort gedruckt bekommen. I denke, kann es etwas falsch in der DBWriter oder anderen Code, den Sie von Ihrer DoScrape-Funktion aufrufen. Vielleicht ist es nicht threadsicher. Das würde erklären, warum das Ausführen aus dem Hauptprogramm direkt funktioniert, aber ein Aufruf von einem Thread schlägt fehl.