Foros del Web » Programando para Internet » Python »

[SOLUCIONADO] Duda con hilos y futures en Python

Estas en el tema de Duda con hilos y futures en Python en el foro de Python en Foros del Web. Hola a todos Estoy intentando crear una clase en Python, para instanciar objetos que luego usare con el método "submit()" de ThreadPoolExecutor. Se supone que ...
  #1 (permalink)  
Antiguo 27/02/2014, 13:04
 
Fecha de Ingreso: febrero-2014
Mensajes: 55
Antigüedad: 10 años, 8 meses
Puntos: 3
Duda con hilos y futures en Python

Hola a todos

Estoy intentando crear una clase en Python, para instanciar objetos que luego usare con el método "submit()" de ThreadPoolExecutor.
Se supone que los objetos tienen que leer un fichero (pasado como param.), buscar su línea mas larga, y devolverla. Este valor devuelto debería ser un future por lo que entiendo.

Para ello creo una clase normal, pero le define el método __call__(), para luego pasarle a submit una instancia de dicha clase, y que utilice el mñetodo __call__(), pero no se si ésto está bien pensado.

El programa funciona, pero se ejecuta de forma secuencial.

No se qué hacer, me he leído la doc, de python varias veces. Creo que no entiendo muy bien el método __call__() y el ThreadPoolExecutor.

Realmente quier "imitar" lo que en java ser haría con una clase implementando Runnable<T> y Future<T>.

Gracias de antemano.

Adjunto el código. Una es la clase "callable" en cuestión, el de abajo es como el "main".

Código:
import threading

class FileThreadCall:
    """
    Thread that reads a file and returns
    this file largest line
    """
    
    def __init__(self,file):
        """
        Contructor
        """
        self.f=file
    
    def __call__(self):
        """
        This method will be called by the
        'submit()' function of 'ThreadPoolExecutor'
        class object 
        """
        return self.__largerLine()
    
    def __largerLine(self):
        """
        search the largest self.f's file
        """
        line=""; aux=""
        for line in self.f:
            if len(line) > len(aux):
                aux=line
        return aux


Código:
from FileThreadCall import *
from concurrent.futures import Executor
from concurrent.futures.thread import ThreadPoolExecutor

def main():
    try:
        fichs = {"f1":open("pr","r"),
                  "f2":open("pr2","r"),
                  "f3":open("pr3","r")}
        future = []
        exe=ThreadPoolExecutor(3)
        for i in range(3):
            future.append(
                exe.submit(FileThreadCall(
                  fichs.get(
                    "f"+str(i+1))
                  )
               )
            )
        for i in range(3):
            print(future[i].result())
    finally:
        for i in range(3):
            fichs.get("f"+str(i+1)).close()
    pass

main()
  #2 (permalink)  
Antiguo 27/02/2014, 20:11
 
Fecha de Ingreso: enero-2012
Ubicación: Buenos Aires
Mensajes: 745
Antigüedad: 12 años, 10 meses
Puntos: 35
Respuesta: Duda con hilos y futures en Python

Creo que es porque en Python no podes ejecutar varios hilos en simultáneo. Por más que los lances todos van a correr secuencialmente.

  #3 (permalink)  
Antiguo 28/02/2014, 05:25
 
Fecha de Ingreso: febrero-2014
Mensajes: 55
Antigüedad: 10 años, 8 meses
Puntos: 3
Respuesta: Duda con hilos y futures en Python

Gracias por la respesta.

Pero si que se pueden ejecutar concurrentemente, de hecho haciendo hilos normales (no callables, si no que hereden de Thread con el método __run__() ) he comprobado que funcionan de forma concurrente. Cada vez en un orden distinto.

Lo que pasa es que los hilos no se pueden ejecutar AL MISMO TIEMPO en 2 CPUs distitnas, pero de forma concurrente claro que sí.

¿alguna otra idea?
  #4 (permalink)  
Antiguo 28/02/2014, 09:06
 
Fecha de Ingreso: enero-2012
Ubicación: Buenos Aires
Mensajes: 745
Antigüedad: 12 años, 10 meses
Puntos: 35
Respuesta: Duda con hilos y futures en Python

Pero realmente no se ejecutan de forma simultánea, simplemente el procesador alterna rápidamente en la ejecución de cada uno de ellos y allí está la ilusión . Así que insisto en que dos hilos no pueden ejecutarse de forma simultánea.
  #5 (permalink)  
Antiguo 04/03/2014, 10:44
AlvaroG
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Duda con hilos y futures en Python

Primero: no importes módulos que no necesitas, solamente complican la lectura del código (threading en tu primer listado, Executor en el segundo). Además, estás importando los símbolos de FileThreadCall.py pero no la clase en sí. Cuidado con eso.

Segundo: Python no tiene un método "main", pero tiene una solución idiomática para la misma funcionalidad.

Tercero: utiliza los iteradores correctamente. No es necesario que uses las formas de comprensión de listas, pero al menos no utilices índices cuando no es necesario.

Tu segundo listado es equivalente al siguiente bloque:
Código Python:
Ver original
  1. from archivo_donde_esta_FileThreadCall import FileThreadCall
  2. from concurrent.futures.thread import ThreadPoolExecutor
  3.  
  4. if __name__ == '__main__':
  5.     try:
  6.         fichs = [ open('pr'), open('pr2'), open('pr3') ]
  7.         exe=ThreadPoolExecutor(3)
  8.         future = [ exe.submit(FileThreadCall(file)) for file in fichs ]
  9.  
  10.         for f in future:
  11.             print(f.result())
  12.  
  13.     finally:
  14.         for file in fichs:
  15.             file.close()

Hechas estas aclaraciones, y luego de ver la documentación del módulo, creo que el problema está en la forma en la que estás mostrando los resultados. Estás llamando al método result() de cada future secuencialmente, cuando lo que hace este método es esperar hasta que el future termina y luego devolver el resultado.

Es decir, en tu bucle for esperas hasta que futures[0] termine, luego a que 1 termine, y luego a que 2 termine. Es ese bloque el que determina que obtengas los resultados secuencialmente.

Para obtener los resultados a medida que se van obteniendo, usa la función as_completed del módulo futures, tal y como está en el ejemplo aquí: http://docs.python.org/dev/library/c...ecutor-example

Cambia tu bucle (línea 10 en el código anterior) por:
Código Python:
Ver original
  1. for f in concurrent.futures.as_completed(future):
  2.     print(f.result())


Saludos.
  #6 (permalink)  
Antiguo 09/03/2014, 10:59
 
Fecha de Ingreso: febrero-2014
Mensajes: 55
Antigüedad: 10 años, 8 meses
Puntos: 3
Respuesta: Duda con hilos y futures en Python

Cita:
Iniciado por AlvaroG Ver Mensaje
Primero: no importes módulos que no necesitas, solamente complican la lectura del código (threading en tu primer listado, Executor en el segundo). Además, estás importando los símbolos de FileThreadCall.py pero no la clase en sí. Cuidado con eso.
No entiendo lo de importar solo los símbolos y la clase, voy a buscar info sobre esto, de todas formas si alguien quiere aclarármelo se lo agradeceré mucho.

Cita:
Iniciado por AlvaroG Ver Mensaje
Segundo: Python no tiene un método "main", pero tiene una solución idiomática para la misma funcionalidad.
Tampoco entiendo a que te refieres, buscaré info también acerca de esto, de nuevo las explicaciones serán muy bien recibidas.

Cita:
Iniciado por AlvaroG Ver Mensaje
Tercero: utiliza los iteradores correctamente. No es necesario que uses las formas de comprensión de listas, pero al menos no utilices índices cuando no es necesario.
Tomo nota.

Cita:
Iniciado por AlvaroG Ver Mensaje
Hechas estas aclaraciones, y luego de ver la documentación del módulo, creo que el problema está en la forma en la que estás mostrando los resultados. Estás llamando al método result() de cada future secuencialmente, cuando lo que hace este método es esperar hasta que el future termina y luego devolver el resultado.

Es decir, en tu bucle for esperas hasta que futures[0] termine, luego a que 1 termine, y luego a que 2 termine. Es ese bloque el que determina que obtengas los resultados secuencialmente.

Para obtener los resultados a medida que se van obteniendo, usa la función as_completed del módulo futures, tal y como está en el ejemplo aquí: [url]http://docs.python.org/dev/library/concurrent.futures.html#threadpoolexecutor-example[/url]

Cambia tu bucle (línea 10 en el código anterior) por:
Código Python:
Ver original
  1. for f in concurrent.futures.as_completed(future):
  2.     print(f.result())


Saludos.
Vale, voy a probar eso, muchas gracias por la aclaración.

Bueno gracias en general por las respuestas, en especial por esta que es muy completa.

PD. Entonces asumo que está bien hecho lo de crear una clase y definir el método __call__() para así hacerla "callable" y que la instanciar el objeto se llame a este método directamente.

EDITO. funciona perfectamente, muchas gracias.

Última edición por SARGE553413; 09/03/2014 a las 11:11
  #7 (permalink)  
Antiguo 10/03/2014, 08:22
AlvaroG
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Duda con hilos y futures en Python

Cita:
Iniciado por SARGE553413 Ver Mensaje
No entiendo lo de importar solo los símbolos y la clase, voy a buscar info sobre esto, de todas formas si alguien quiere aclarármelo se lo agradeceré mucho.
En Java declarás paquetes y clases de tal manera que el archivo Clase.java contiene una clase pública Clase, se compila a Clase.class y se importa como
Código Java:
Ver original
  1. import paquete.Clase
En Python, tenés paquetes y módulos (archivos .py), y los módulos exportan sus variables, funciones, y clases globales (al módulo). Suponiendo que tengas un archivo ejemplo.py con el siguiente contenido:
Código Python:
Ver original
  1. mi_variable = 1
  2.  
  3. def mi_funcion():
  4.     pass
existen dos formas de utilizar mivariable y mi_funcion:
Código Python:
Ver original
  1. import ejemplo
  2. from ejemplo import mi_variable, mi_funcion
en el primer caso, deberías referir a la variable y a la función como ejemplo.mi_variable y ejemplo.mi_funcion, mientras que en el segundo caso los podés usar directamente.

El import que usaste en tu primer ejemplo me hizo pensar que estabas intentando importar como se hace en Java y otros lenguajes, por eso mi comentario.

Cita:
Iniciado por SARGE553413 Ver Mensaje
Tampoco entiendo a que te refieres, buscaré info también acerca de esto, de nuevo las explicaciones serán muy bien recibidas.
Pues lo que escribí, en Python no hay un método "main" que de inicio al programa. Cuando ejecutas un archivo Python el código que contiene se ejecuta secuencialmente.
Para hacer que un bloque de código se ejecute solamente si el archivo (módulo) se ejecuta como un programa independiente, se utiliza el condicional "if __name__ == '__main__'"


Saludos.

Etiquetas: hilos
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 10:00.