Mini - Ladrillo
En determinadas ocasiones, resulta necesario ejecutar varias tareas al mismo tiempo para ganar en velocidad de proceso.
Estas tareas pueden ser similares o bien diferentes y a veces utilizan el mismo recurso simultaneamente o bien necesitan comunicarse entre ellos para coordinarse; esto puede dar problemas, pero la programación multihilo nos permite solucionar estas situaciones mediante varios recursos, cada uno adecuado o necesario en un caso u otro.
Estos recursos son :
- Semáforos. Permiten acceder a un recurso y liberarlo cuando queramos.
- Bloqueos. Bloquean el recurso hasta que es liberado para su reutilización por parte de otro hilo.
- Condiciones. Este caso es similar a los anteriores, pero permite notificar cuando el recurso es liberado.
En los 3 casos, podemos definir el número de accesos simultáneos. Podría ser 1, 2 o los que queramos, siempre y cuando el recurso a utilizar aguante dicha carga sin fallar.
El Código
Comenzamos con algo sencillo: un solo hilo que se ejecuta de forma simultánea al hilo principal.
#!/usr/bin/python
import threading
import time
def hilo(i):
""":param i: numero de hilo a efectos ilustrativos :return: nada """
print "[+] En hilo %d\n" % i
time.sleep(3)
print "[-] hilo %d finalizado"
# Creacion y Ejecucion de 1 hilo paralelo a hilo 2
simplethread=threading.Thread(target=hilo, args=[1])
simplethread.start()
# Esto se ejecuta como proceso principal
hilo(2) # Esperamos a que acabe el hilo paralelo 1
simplethread.join()
En este caso, no hay interacción ni compartimos recursos: 1 hilo, 1 proceso principal.
En el siguiente caso, ya, vamos a ejecutar varios hilos simultáneamente. No compartimos recursos ni hay sincronía alguna entre procesos.
#!/usr/bin/python
import threading
import time
NTHREADS=20
def hilo(i):
""" :param i: numero de hilo a efectos ilustrativos :return: nada """
print "[+] En hilo %d" % i
time.sleep(3)
print "[-] hilo %d finalizado" % i
simplethread=[]
for i in range(NTHREADS):
# arranque y comienzo de hilo num i+1
simplethread.append(threading.Thread(target=hilo, args=[i+1]))
simplethread[-1].start()
for i in range(NTHREADS):
# esperamos que acabe el hilo num i
simplethread[i].join()
print "[*] all threads finished"
En este ejemplo, usamos semáforos, que son la forma mas primitiva de compartir recursos. El ejemplo consiste en la salida por un tunel por parte de varias personas. Solo puede entrar una a la vez.
#!/usr/bin/python
import threading
from threading import Semaphore
import time
NTHREADS=20
WIDTH=1
sem=Semaphore(WIDTH)
def hilo(i):
""":param i: numero de hilo a efectos ilustrativos :return: nada """
print "[+] En hilo %d" % i
time.sleep(3)
sem.acquire()
print "[+] En tunel hilo %d" % i
time.sleep(1)
sem.release()
print "[-] hilo %d, estoy fuera" % i
simplethread=[]
for i in range(NTHREADS):
# arranque y comienzo de hilo num i+1
simplethread.append(threading.Thread(target=hilo, args=[i+1]))
simplethread[-1].start()
for i in range(NTHREADS):
# esperamos que acabe el hilo num i
simplethread[i].join()
print "[*] all"
El siguiente ejemplo, ilustra los bloqueos de recursos. En este caso RLock.
Simula varias personas bebiendo de un solo vaso. Todos beben a la misma velocidad.
#!/usr/bin/python
import threading
from threading
import RLock
import time
THREADS=20 # Bloqueo de un recurso mientras se usa
sem=RLock()
def hilo(i):
""" :param i: numero de hilo a efectos ilustrativos :return: nada """
print "[+] En hilo %d" % i
time.sleep(3)
with sem:
print "[+] Bebiendo hilo %d..." % i
time.sleep(1)
print "[-] hilo %d satisfecho" % i
simplethread=[]
for i in range(NTHREADS):
# arranque y comienzo de hilo num i+1
simplethread.append(threading.Thread(target=hilo, args=[i+1]))
simplethread[-1].start()
for i in range(NTHREADS):
""" # esperamos que acabe el hilo num i"""
simplethread[i].join()
print "[*] all threads finished"
Para terminar, ilustraré las Conditions. Estas formas de bloqueo de recursos son las más sofisticadas que hay. En el ejemplo, seguimos bebiendo, esta vez, cada uno bebe a su ritmo y notifica cuando terminó de beber al resto.
#!/usr/bin/python
import threading
from threading import Condition
import time
from random import randint
NTHREADS=20
# Bloqueo de un recurso mientras se usa
sem=Condition()
def bebe(i):
s=randint(1,10)
print "[+] Bebiendo hilo %d.. esperate %d secs" % (i,s)
time.sleep(s)
sem.notify(1)
print "[-] estaba de muerte, hilos --%d--" % i
sem.release()
def hilo(i):
""" :param i: numero de hilo a efectos ilustrativos :return: nada """
print "[+] En hilo %d" % i
time.sleep(1)
while not sem.acquire():
sem.wait(0.5)
else:
bebe(i)
print "[-] hilo %d finalizado" % i
simplethread=[]
for i in range(NTHREADS):
# arranque y comienzo de hilo num i+1
simplethread.append(threading.Thread(target=hilo, args=[i+1]))
simplethread[-1].start()
for i in range(NTHREADS):
# esperamos que acabe el hilo num i
simplethread[i].join()
print "[*] all threads finished"
Espero que os haya interesado el artículo y muchas gracias por la lectura.
Saludos y hasta la proxima.
Descarga el codigo demos_multihilo.tar.gz
blog comments powered by