2016-10-21 6 views
1

Ich lade Bilder aus dem Internet, und wie sich herausstellt, muss ich viele Bilder herunterladen. Ich verwende eine Version des folgenden Code-Fragment (tatsächlich durch die Links Looping Ich beabsichtige, die Bilder zum Download und Download:Beschleunigung urlib.urlretrieve

import urllib 
urllib.urlretrieve(link, filename) 

Ich lade etwa 1000 Bilder alle 15 Minuten, die furchtbar langsam auf die Zahl basiert herunterladen von Bildern muss ich

Für Effizienz, ich habe einen Timeout alle 5 Sekunden (noch viele Downloads viel länger dauern.):

import socket 
socket.setdefaulttimeout(5) 

Neben einen Job auf einem Computer-Cluster ausgeführt Downloads parallelisieren, wird Da ist es um das Bild schneller/effizienter zu machen?

+0

Ich denke, das könnte Sie begeistern: http://stackoverflow.com/questions/1628766/python-package-for-multi-threaded-spider-w-proxy-support – snahor

+0

Schauen Sie in Pakete wie scrapy oder twisted. Scrapy basiert auf Twisted, aber ein bisschen einfacher zu bedienen. Beide bieten eine nicht blockierende API. Auf diese Weise können Sie mehrere Dateien als eine Datei herunterladen. ** Sei einfach nett und beschränke die Anzahl der parallelen Downloads vom selben Server ** –

+0

Hallo Tammo, vielen Dank. Btw, ich fand einen ausgezeichneten Artikel, der scrappy mit urllib2 vergleicht: http://www.scrapinginsider.com/2016/01/scrapy-urllib2-requests-beautifulsoup-lxml.html - auch glaube ich, dass Multithreading die Leistung erheblich verbessern kann des obigen Codes. Sobald ich genau herausgefunden habe, wie es geht, werde ich eine Antwort schreiben –

Antwort

1

Mein Code oben war sehr naiv, da ich Multi-Threading nicht genutzt habe. Es dauert natürlich, dass URL-Anfragen beantwortet werden, aber es gibt keinen Grund, warum der Computer keine weiteren Anfragen machen kann, während der Proxy-Server antwortet.

Mit den folgenden Anpassungen können Sie die Effizienz um das 10-fache verbessern - und es gibt weitere Möglichkeiten zur Verbesserung der Effizienz mit Paketen wie Scrapy.

Multi-Threading hinzuzufügen, gehen Sie so etwas wie die folgenden, das Multiprocessing-Paket mit:

1) kapselt die URL in einer Funktion abrufen:

import import urllib.request 

def geturl(link,i): 
try: 
    urllib.request.urlretrieve(link, str(i)+".jpg") 
except: 
    pass 

2) dann eine Sammlung mit allen erstellen Urls sowie Namen, die Sie für die heruntergeladenen Bilder werden soll:

urls = [url1,url2,url3,urln] 
names = [i for i in range(0,len(urls))] 

3) aus dem Multiprocessing-Paket die Pool-Klasse importieren und ein Objekt unter Verwendung eines solchen cla erstellen ss (natürlich würden Sie alle Importe in der ersten Zeile des Codes in einem realen Programm enthalten):

from multiprocessing.dummy import Pool as ThreadPool 
pool = ThreadPool(100) 

dann die pool.starmap() -Methode verwenden und die Funktion und die Argumente der Funktion übergeben.

results = pool.starmap(geturl, zip(links, d)) 

Anmerkung: pool.starmap() funktioniert nur in Python 3

0

Wenn ein Programm in I/O-Wartezeit, wird die Ausführung angehalten, so dass der Kern der Low-Level-Operationen mit dem zugehörigen ausführen kann E/A-Anforderung (dies wird context switch) genannt und wird nicht fortgesetzt, bis die E/A-Operation abgeschlossen ist.

Kontextwechsel ist eine ziemlich schwere Operation. Es erfordert, dass wir den Status unseres Programms speichern (jede Art von verlieren Caching hatten wir auf der CPU-Ebene) und geben die Nutzung der CPU auf. Später, wenn wir wieder laufen dürfen, müssen wir Zeit reinitialisieren nisieren unser Programm auf dem Motherboard und machen Sie sich bereit für die Fortsetzung (natürlich geschieht dies alles hinter den Kulissen).

Mit concurrency, auf der anderen Seite haben wir in der Regel eine Sache namens "Event-Loop" ausgeführt, die verwaltet, was in unserem Programm ausgeführt wird, und wann. Im Wesentlichen ist eine Ereignisschleife einfach eine Liste von Funktionen, die ausgeführt werden müssen. Die Funktion an der Spitze der Liste wird ausgeführt, dann die nächste usw.

Die folgende Abbildung zeigt ein einfaches Beispiel für eine Ereignisschleife:

from Queue import Queue 
from functools import partial 

eventloop = None 

class EventLoop(Queue): 
    def start(self): 
     while True: 
      function = self.get() 
      function() 

def do_hello(): 
    global eventloop 
    print "Hello" 
    eventloop.put(do_world) 

def do_world(): 
    global eventloop 
    print "world" 
    eventloop.put(do_hello) 

if __name__ == "__main__": 
    eventloop = EventLoop() 
    eventloop.put(do_hello) 
    eventloop.start() 

Wenn die oben wie etwas scheint, dass Sie verwenden können, und Sie würden auch zu sehen, wie gevent,tornado, und AsyncIO, mit Ihrem Problem helfen können Dann geh in deine (Universitäts-) Bibliothek, sieh dir High Performance Python by Micha Gorelick and Ian Ozsvald an und lies die Seiten 181-202.

Hinweis: obigen Code und Text sind von der book erwähnt.