Cómo hacer una recuperación de URL sin locking en Python

Estoy escribiendo una aplicación GUI en Pyglet que tiene que mostrar de decenas a cientos de miniaturas desde Internet. En este momento, estoy usando urllib.urlretrieve para agarrarlos, pero esto se bloquea cada vez hasta que se terminan, y solo se agarra uno a la vez.

Preferiría descargarlos en paralelo y hacer que cada uno se muestre tan pronto como haya terminado, sin bloquear la GUI en ningún momento. ¿Cuál es la mejor manera de hacer esto?

No sé mucho acerca de los subprocesos, pero parece que el módulo de subprocesos podría ayudar. O tal vez hay alguna manera fácil que he pasado por alto.

Probablemente se beneficiará de multiprocessing módulos de threading o multiprocessing . No necesitas crear todas esas clases basadas en Thread por ti mismo, hay un método más simple usando 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) 

Como sospechaba, esta es una situación perfecta para enhebrar. Aquí hay una breve guía que encontré de inmensa ayuda al hacer mi primera parte de enhebrar en python.

Como ha indicado correctamente, puede crear una serie de subprocesos, cada uno de los cuales es responsable de realizar las operaciones de recuperación de URL. Esto permite que el hilo principal continúe sin interrupciones.

Aquí hay un tutorial sobre cómo enhebrar en python: http://heather.cs.ucdavis.edu/~matloff/Python/PyThreads.pdf

Aquí hay un ejemplo de cómo usar threading.Thread. Simplemente reemplaza el nombre de la clase con el tuyo y la función de ejecución con el tuyo. Tenga en cuenta que el subprocesamiento es ideal para aplicaciones restringidas de E / S como la suya y realmente puede acelerarlo. El uso de subprocesos pythong estrictamente para el cálculo en python estándar no ayuda porque solo se puede calcular un subproceso a la vez.

 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 

Tienes estas opciones:

  • Hilos: más fáciles pero no se escalan bien
  • Torcido: dificultad media, escala bien pero comparte la CPU debido a GIL y al ser de un solo hilo.
  • Multiprocesamiento: el más duro. Escala bien si sabes cómo escribir tu propio bucle de eventos.

Recomiendo usar solo hilos a menos que necesite un buscador a escala industrial.

Debe usar subprocesos o una biblioteca de red asíncrona como Twisted . Sospecho que el uso de hilos puede ser más simple en su caso de uso particular.