2016-11-23 2 views
1

die folgende Klasse Gegeben:Kann ich davon ausgehen, dass meine Threads fertig sind, wenn threading.active_count() 1 zurückgibt?

from abc import ABCMeta, abstractmethod 
from time import sleep 
import threading 
from threading import active_count, Thread 

class ScraperPool(metaclass=ABCMeta): 
    Queue = [] 
    ResultList = [] 

    def __init__(self, Queue, MaxNumWorkers=0, ItemsPerWorker=50): 
     # Initialize attributes 
     self.MaxNumWorkers = MaxNumWorkers 
     self.ItemsPerWorker = ItemsPerWorker 
     self.Queue = Queue # For testing purposes. 

    def initWorkerPool(self, PrintIDs=True): 
     for w in range(self.NumWorkers()): 
      Thread(target=self.worker, args=(w + 1, PrintIDs,)).start() 
      sleep(1) # Explicitly wait one second for this worker to start. 

    def run(self): 
     self.initWorkerPool() 

     # Wait until all workers (i.e. threads) are done. 
     while active_count() > 1: 
      print("Active threads: " + str(active_count())) 
      sleep(5) 

     self.HandleResults() 

    def worker(self, id, printID): 
     if printID: 
      print("Starting worker " + str(id) + ".") 

     while (len(self.Queue) > 0): 
      self.scraperMethod() 

     if printID: 
      print("Worker " + str(id) + " is quiting.") 

     # Todo Kill is this Thread. 

     return 

    def NumWorkers(self): 
     return 1 # Simplified for testing purposes. 

    @abstractmethod 
    def scraperMethod(self): 
     pass 

class TestScraper(ScraperPool): 
    def scraperMethod(self): 
     # print("I am scraping.") 
     # print("Scraping. Threads#: " + str(active_count())) 
     temp_item = self.Queue[-1] 
     self.Queue.pop() 

     self.ResultList.append(temp_item) 

    def HandleResults(self): 
     print(self.ResultList) 

ScraperPool.register(TestScraper) 

scraper = TestScraper(Queue=["Jaap", "Piet"]) 
scraper.run() 
print(threading.active_count()) 
# print(scraper.ResultList) 

Wenn alle Threads fertig sind, gibt es immer noch einen aktiven Thread - threading.active_count() in der letzten Zeile wird mir diese Nummer. Das aktive Gewinde ist <_MainThread(MainThread, started 12960)> - wie mit threading.enumerate() gedruckt.

Kann ich davon ausgehen, dass alle meine Threads fertig sind, wenn active_count() == 1? Oder importieren importierte Module zum Beispiel zusätzliche Threads, so dass meine Threads tatsächlich fertig sind, wenn active_count() > 1 - auch die Bedingung für die Schleife, die ich in der run-Methode verwende.

+0

Die 'Klasse TestScraper():' Zeile fehlt? – cat

+0

Um die Dinge einfach zu halten, habe ich nur einen Teil des Codes gepostet. Ich habe jetzt einen Pastebin-Link zum vollständigen Skript hinzugefügt. – user2693053

+0

Der Code, den Sie posten, muss minimal, vollständig und überprüfbar sein ([mcve]), und dies scheint Importe und Definitionen zu vermissen. – cat

Antwort

2

können Sie davon ausgehen, dass Ihre Threads sind fertig, wenn active_count() 1. Das Problem erreicht wird, wenn ein anderes Modul einen Thread erstellt, die Sie nie sollten Sie zu 1. bekommen Verwalten Sie Ihre Threads explizit.

Beispiel: Sie können die Threads in eine Liste einfügen und sie einzeln verbinden. Die relevanten Änderungen an Ihrem Code sind:

def __init__(self, Queue, MaxNumWorkers=0, ItemsPerWorker=50): 
    # Initialize attributes 
    self.MaxNumWorkers = MaxNumWorkers 
    self.ItemsPerWorker = ItemsPerWorker 
    self.Queue = Queue # For testing purposes. 
    self.WorkerThreads = [] 

def initWorkerPool(self, PrintIDs=True): 
    for w in range(self.NumWorkers()): 
     thread = Thread(target=self.worker, args=(w + 1, PrintIDs,)) 
     self.WorkerThreads.append(thread) 
     thread.start() 
     sleep(1) # Explicitly wait one second for this worker to start. 

def run(self): 
    self.initWorkerPool() 

    # Wait until all workers (i.e. threads) are done. Waiting in order 
    # so some threads further in the list may finish first, but we 
    # will get to all of them eventually 
    while self.WorkerThreads: 
     self.WorkerThreads[0].join() 

    self.HandleResults() 
+0

Ich war ursprünglich verfolgen die aktiven Scraper in einem Integer 'scraperpool.ActiveWorkersCount', die inkrementiert/dekrementiert wurde, wenn ein Arbeiter gestartet/gestoppt. Ich lief dann in 'threading.active_count()' und versuchte, diese Methode zu verwenden. Ist mein ursprünglicher Ansatz, was Sie mit "Verwalten Sie Ihre Threads" meinen? – user2693053

+0

er bedeutet, dass Sie sich ihnen explizit anschließen sollten .... – user3012759

+0

Ich glaube nicht, dass ich ruhig 'threading.join()' verstehe, aber ich muss mich darum kümmern. Können Sie ein Beispiel geben? – user2693053

2

nach docsactive_count() umfasst den Haupt-Thread, wenn Sie also auf 1 sind, dann sind Sie wahrscheinlich getan, aber wenn Sie eine andere Quelle für neue Themen in Ihrem Programm haben, dann können Sie vor active_count() Treffer 1 durchgeführt werden.

würde ich empfehlen, auf ScraperPool explizite join Verfahren implementiert und Ihre Mitarbeiter zu verfolgen und sie explizit zur Haupt Anspinnen bei der Überprüfung statt erforderlich, dass Sie mit active_count() Anrufen fertig sind.

auch über GIL erinnern ...

+0

Es stimmt, dass wenn Sie bei 1 sind, Sie fertig sind. Aber wenn ein anderes Modul einen Thread erstellt, werden Sie nie zu 1. Das ist, was OP fragt. – tdelaney

+0

@tdelaney das ist, was ich gesagt habe ... – user3012759

Verwandte Themen