Come fare un URL non bloccante recuperare in Python
-
13-09-2019 - |
Domanda
Sto scrivendo un'applicazione GUI in pyglet che deve visualizzare decine a centinaia di miniature da Internet . In questo momento, sto utilizzando urllib.urlretrieve ad afferrarli, ma questo blocca ogni volta fino a quando non sono finiti, e afferra solo uno alla volta.
Io preferirei di scaricarli in parallelo e hanno ciascuno display non appena è finito, senza bloccare l'interfaccia grafica in qualsiasi momento. Qual è il modo migliore per fare questo?
Non so molto circa le discussioni, ma sembra che il filettatura modulo potrebbe aiutare? O forse c'è un modo semplice che ho trascurato.
Soluzione
Probabilmente beneficiare di threading
o multiprocessing
moduli . In realtà non è necessario creare tutte quelle classi Thread
a base da soli, c'è un metodo più semplice utilizzando Pool.map
:
from multiprocessing import Pool
def fetch_url(url):
# Fetch the URL contents and save it anywhere you need and
# return something meaningful (like filename or error code),
# if you wish.
...
pool = Pool(processes=4)
result = pool.map(f, image_url_list)
Altri suggerimenti
Come si sospetta, questa è una situazione ideale per la filettatura. Qui è una breve guida che ho trovato immensamente utile quando si fa il mio primo pezzo di filettatura in Python.
Come lei ha giustamente indicato, è possibile creare un numero di thread, ognuno dei quali è responsabile per l'esecuzione di operazioni urlretrieve. Questo permette al filo principale applicazione continua.
Ecco un tutorial sulla filettatura in pitone: http://heather.cs.ucdavis.edu/~matloff/Python/ PyThreads.pdf
Ecco un esempio di come utilizzare threading.Thread. Basta sostituire il nome della classe con il proprio e la funzione di corsa con il proprio. Si noti che threading è grande per IO limitato le applicazioni come il vostro di e può davvero accelerarlo. Utilizzando pythong filettatura esclusivamente per il calcolo in pitone norma non aiuta perché solo un thread può calcolare alla volta.
import threading, time
class Ping(threading.Thread):
def __init__(self, multiple):
threading.Thread.__init__(self)
self.multiple = multiple
def run(self):
#sleeps 3 seconds then prints 'pong' x times
time.sleep(3)
printString = 'pong' * self.multiple
pingInstance = Ping(3)
pingInstance.start() #your run function will be called with the start function
print "pingInstance is alive? : %d" % pingInstance.isAlive() #will return True, or 1
print "Number of threads alive: %d" % threading.activeCount()
#main thread + class instance
time.sleep(3.5)
print "Number of threads alive: %d" % threading.activeCount()
print "pingInstance is alive?: %d" % pingInstance.isAlive()
#isAlive returns false when your thread reaches the end of it's run function.
#only main thread now
Sono disponibili le seguenti opzioni:
- Discussioni: più semplice, ma non scala bene
- twisted:. Media difficoltà, scala bene ma condivide CPU a causa di GIL e di essere a thread singolo
- Multiprocessing: più difficile. Scala bene se si sa come scrivere il proprio ciclo di eventi.
Mi raccomando solo usando le discussioni a meno che non avete bisogno di un Fetcher scala industriale.
Si sia bisogno di usare i thread, o una libreria di rete asincrono come ritorto . Ho il sospetto che l'uso di fili potrebbe essere più semplice nel vostro particolare caso d'uso.