2016-07-29 46 views
2

Ich habe versucht, meinen ersten Versuch an einem Thread-Skript zu machen. Es wird schließlich ein Web-Scraper sein, der hoffentlich ein wenig schneller arbeitet als das ursprüngliche lineare Scraping-Skript, das ich zuvor gemacht habe.Python Threading/Thread-Implementierung

Nach Stunden des Lesens und Spielen mit einigen Beispielcode. Ich bin mir immer noch nicht sicher, was als richtig angesehen wird, soweit eine Implementierung geht.

Zur Zeit habe ich den folgenden Code, die ich mit gespielt:

from Queue import Queue 
import threading 

def scrape(queue): 
    global workers 
    print worker.getName() 
    print queue.get() 
    queue.task_done() 
    workers -= 1 

queue = Queue(maxsize=0) 
threads = 10 
workers = 0 


with open('test.txt') as in_file:  
    for line in in_file: 
     queue.put(line) 

while not (queue.empty()): 
    if (threads != workers): 
     worker = threading.Thread(target=scrape, args=(queue,)) 
     worker.setDaemon(True) 
     worker.start() 
     workers += 1 

Die Idee ist, dass ich eine Liste von URLs in der test.txt-Datei haben. Ich öffne die Datei und lege alle URLs in die Warteschlange. Von dort bekomme ich 10 Threads, die aus der Warteschlange ziehen und eine Webseite abkratzen, oder in diesem Beispiel einfach die gezogene Zeile ausdrucken.

Sobald die Funktion fertig ist, entferne ich einen "Worker Thread" und dann ersetzt ein neuer es, bis die Warteschlange leer ist.

In meiner realen Welt Implementierung irgendwann werde ich die Daten aus meiner Funktion scrapes nehmen und es in eine .csv-Datei schreiben müssen. Aber im Moment versuche ich nur zu verstehen, wie man die Threads korrekt implementiert.

Ich habe ähnliche Beispiele wie oben gesehen, die 'Thread' verwenden ... und ich habe auch 'threading' Beispiele gesehen, die eine geerbte Klasse verwenden. Ich möchte nur wissen, was ich verwenden soll und wie man es richtig handhaben kann.

Gehen Sie einfach auf mich hier, Im nur ein Anfänger versucht, Threads zu verstehen .... und ja, ich weiß, dass es sehr kompliziert werden kann. Ich denke jedoch, dass dies für einen ersten Versuch einfach genug sein sollte ...

+0

Threading im Allgemeinen ist ziemlich komplex und die meiste Zeit ist es einfacher, eine Abstraktionsbibliothek wie Multiprocessing (.dummy) oder concurrent.futures – janbrohl

Antwort

2

Auf Python 2.x multiprocessing.dummy (die Threads verwendet) ist eine gute Wahl, wie es einfach zu bedienen ist (auch in Python 3.x möglich)

Wenn Sie herausfinden, Scraping ist CPU-begrenzt und Sie haben mehrere CPU-Kerne, auf diese Weise können Sie ganz einfach auf echte multiprocessing wechseln, möglicherweise eine große Beschleunigung zu gewinnen.

(Python oft nicht mit Gewinde so viel wie mit mehreren Prozessen wegen eines performance optimization von mehreren CPUs profitieren - müssen Sie selbst herausfinden, was in Ihrem Fall ist schneller)

Mit mutliprocessing.dummy Sie tun können,

from multiprocessing.dummy import Pool 
# from multiprocessing import Pool # if you want to use more cpus 

def scrape(url): 
    data = {"sorted": sorted(url)} # normally you would do something more interesting 
    return (url, data) 

urls=[] 
threads = 10 

if __name__=="__main__": 
    with open('test.txt') as in_file:  
     urls.extend(in_file) # lines 

    p=Pool(threads) 
    results=list(p.imap_unordered(scrape,urls)) 
    p.close() 
    print results # normally you would process your results here 

Auf Python 3.x concurrent.futures könnte eine bessere Wahl sein.

+0

zu verwenden. Das scheint mir auf den ersten Blick viel einfacher zu sein. Außerdem ist es schneller, wenn man ein wenig herumspielt. Ein Problem, mit dem ich beim Scraping-Teil des Skripts konfrontiert wurde, ist, dass ich Variablen teile, die ich nicht teilen möchte, wie die Scraped-Informationen, die ich versuche, in .csv zu schreiben. Wenn ich 5 Threads starte, um mit dem Scraping zu beginnen, erhalte ich 5 Duplikate, die in meinen CSV geschrieben werden, obwohl der Scraper die Seiten, die ich möchte, richtig besucht. Wenn ich meine Threads Lock() und Release() lösche, läuft das Script dann einfach wieder linear. Wie kann ich verhindern, dass meine Threads die anderen Daten überschreiben? –

+0

Wenn Sie keine Informationen zwischen Threads/Prozessen teilen möchten, die Sie später zusammenstellen möchten, setzen Sie das in den Rückgabewert Ihrer Scrape-Funktion - nicht in Variablen außerhalb Ihrer Funktion schreiben, wenn Sie nicht müssen – janbrohl

+0

Ich muss ich sagen habe von deinem Beispielcode viel über Threads und Multiprocessing gelernt. Ich wollte dir nur danken. Außerdem stellte sich heraus, dass das Multiprocessing viel schneller und sauberer war, um IMO zu implementieren. Nur neugierig, ob das das Modul der Wahl für professionelle Entwickler ist? Oder gibt es einen Vorteil für Low-Level-Thread-Module? –