Barreras en Python

Es un método de sincronización. Una barrera para un grupo de hilos o procesos significa que todos los que implementen esta barrera deberán parar en ese punto sin poder ejecutar las siguientes líneas de código hasta que todos los restantes hilos/procesos hayan alcanzado esta barrera.

Construcciones barrera clásicas definen el conjunto de procesos / hilos de participar de forma estática. Esto suele hacerse, ya sea al inicio del programa o cuando una barrera como el Pthreads barrera se crea una instancia. Esto restringe las posibles aplicaciones para las que se pueden utilizar barreras.

Apoyar paradigmas de programación más dinámicos como tenedor / unirse paralelismo, los conjuntos de los participantes tienen que ser dinámicos. Por lo tanto, necesita el conjunto de procesos / hilos que participan en una operación de barrera para ser capaz de cambiar con el tiempo. X10 introdujo el concepto de los relojes para tal fin, que proporcionan una barrera dinámica semántica. Sobre la base de los relojes, sincronizadores . Se han propuesto para añadir aún más flexibilidad para la sincronización de barrera. Con sincronizadores es posible expresar dependencias de datos entre los procesos que participan de forma explícita para evitar innecesaria sobre-sincronización.

Barrera (partes [, la acción [, timeout]])

Crear una compartida threading.Barrier objeto y devolver un proxy para ello.

counters = [0, 0]

barrier = threading.Barrier(2)

def count(thread_num, steps):

for i in range(steps):

other = counters[1 – thread_num]

barrier.wait() # wait for reads to complete

counters[thread_num] = other + 1

barrier.wait() # wait for writes to complete

def threaded_count(steps):

other = threading.Thread(target=count, args=(1, steps))

other.start()

count(0, steps)

print(‘counters:’, counters)

threaded_count(10)

En este ejemplo, la lectura y la escritura a los datos compartidos tienen lugar en diferentes fases, separados por barreras. Las escrituras se producen en la misma fase, pero son disjuntos; esta disjunción es necesario para evitar escrituras concurrentes a los mismos datos en la misma fase.Puesto que este código está sincronizada correctamente, ambos contadores siempre serán 10 en el extremo.

La partícula multiproceso simulador utiliza una barrera de una manera similar para sincronizar el acceso a los datos compartidos. En la simulación, cada hilo posee un número de partículas, todos los cuales interactúan entre sí a lo largo de muchos timesteps discretos. Una partícula tiene una posición, velocidad y aceleración, y una nueva aceleración se calcula en cada paso de tiempo basado en las posiciones de las otras partículas. La velocidad de la partícula debe ser actualizado en consecuencia, y su posición de acuerdo con su velocidad.

Al igual que con el simple ejemplo de arriba, hay una fase de lectura, en la que todas las posiciones de las partículas “son leídas por todos los temas. Cada hilo actualiza la aceleración de sus propias partículas ‘en esta fase, pero ya que estas son las escrituras disjuntos, no tiene por qué ser sincronizado. En la fase de escritura, cada hilo actualiza velocidades y posiciones de sus propias partículas. Una vez más, estos son escrituras disjuntos, y están protegidos de la fase de lectura por barreras.

Referencias:

http://composingprograms.com/pages/47-parallel-computing.html

https://docs.python.org/3/library/multiprocessing.html

Semáforos en Python

fondo

Ésta es una de las más antiguas primitivas de sincronización de la historia de la ciencia informática. Fue inventada por el informático teórico holandés Edsger W. Dijkstra (él utilizaba P() y V() en lugar de acquire() y release()).

Un semáforo actúa como un contador con un valor inicial.

  • Cada vez que un hilo llama a Semaphore.acquire(), el contador se decrementa en 1 y se deja pasar al hilo. En el momento que el contador se hace cero, NO se deja pasar al siguiente hilo que llame a acquire(), sino que lo deja bloqueado.
  • Cada vez que se llama a Semaphore.release(), el contador se incrementa en 1. Si se hace igual a cero, libera al siguiente hilo en la cola de espera.

Un semáforo gestiona un contador interno que se decrementa en cada llamada a acquire() y se incrementa en cada llamada a release(). El contador nunca puede bajar de cero. Si una llamada a acquire() se encuentra el contador a cero, bloquea la ejecución del hilo en curso y queda a la espera de que otro hilo llame arelease().

Semaphore ([value])

El argumento opcional proporciona el valor inicial del contador interno. El valor predeterminado es 1.

acquire ([blocking])

Adquirir un semáforo.

Si se invoca sin argumentos: si el contador interno es superior a cero a la entrada, lo decrementa en una unidad y retorna de inmediato. Si es cero a la entrada, bloquear la ejecución del hilo, esperando a que otro llame a release() para hacerlo mayor de cero. Se gestionan de manera adecuada los interbloqueos, por lo que si hay varias llamadas a acquire() bloqueadas a la espera, release() despertará exactamente a una de ellas. La implementación puede seleccionar una al azar, por lo que no se debe confiar en un orden de respuesta observado. No hay valor de retorno en este caso.

Si se invoca con el argumento blocking a verdadero, hacer lo mismo que si se llama sin argumentos y devolver verdadero.

Si se invoca con blocking a falso, no bloquear. Si una llamada sin argumentos bloquearía, devolver falso de inmediato. En caso contrario, hacer lo mismo que si se llama sin argumentos y devolver verdadero.

release ()

Liberar un semáforo, incrementando su contador interno en una unidad. Si era cero a la entrada y otro hilo está esperando a que sea mayor que cero, despertar a dicho hilo.

Para ver su funcionamiento basta observar el siguiente ejemplo sencillo. En anteriores entradas del blog podemos observar todo lo relativo al módulo Threading. Por otro lado, se debe crear el semáforo indicando el valor inicial del contador (número máximo de hilos que pueden estar activos simultáneamente):

import threading

from time import sleep

n_sem = 1

semaforo = threading.Semaphore(n_sem)

class Hilo(threading.Thread):

def __init__(self, id):

threading.Thread.__init__(self)

self.id = id

def run(self):

semaforo.acquire()

print “Hilo %s entra.”%(self.id)

sleep(3)

semaforo.release()

hilos = [Hilo(1), Hilo(2), Hilo(3)]

for h in hilos:

h.start()

Referencias:

http://pyspanishdoc.sourceforge.net/lib/semaphore-objects.html

https://pythonr2.wordpress.com/2008/09/01/sincronizacion-de-hilos-en-python/

http://mundogeek.net/archivos/2008/04/18/threads-en-python/