¿Son innecesarios los bloqueos en el código Python multiproceso debido al GIL?

Si confía en una implementación de Python que tiene un bloqueo de intérprete global (es decir, CPython) y escribe código multiproceso, ¿realmente necesita bloqueos?

Si el GIL no permite que se ejecuten varias instrucciones en paralelo, ¿no sería innecesario proteger los datos compartidos?

lo siento si esta es una pregunta tonta, pero es algo que siempre me he preguntado sobre Python en máquinas multiprocesador / núcleo.

lo mismo se aplicaría a cualquier otra implementación de lenguaje que tenga un GIL.

Respuestas:9 Respuestas 9
Tiempo:hace 13 años, 11 meses
Última modificación:hace 7 años, 9 meses

Solución

Seguirá necesitando bloqueos si comparte el estado entre subprocesos. El GIL solo protege al intérprete internamente. Aún puede tener actualizaciones inconsistentes en su propio código.

Por ejemplo:

#!/usr/bin/env python
import threading

shared_balance = 0

class Deposit(threading.Thread):
    def run(self):
        for _ in xrange(1000000):
            global shared_balance
            balance = shared_balance
            balance += 100
            shared_balance = balance

class Withdraw(threading.Thread):
    def run(self):
        for _ in xrange(1000000):
            global shared_balance
            balance = shared_balance
            balance -= 100
            shared_balance = balance

threads = [Deposit(), Withdraw()]

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

print shared_balance

Aquí, su código puede interrumpirse entre la lectura del estado compartido () y la escritura del resultado modificado (), lo que provoca una actualización perdida. El resultado es un valor aleatorio para el estado compartido.balance = shared_balanceshared_balance = balance

Para que las actualizaciones sean coherentes, los métodos de ejecución tendrían que bloquear el estado compartido alrededor de las secciones de lectura,modificación-escritura (dentro de los bucles) o tener alguna forma de detectar cuándo había cambiado el estado compartido desde que se leyó.

Otras respuestas

Piénsalo de esta manera:

En una computadora con un solo procesador, el subproceso múltiple ocurre suspendiendo un subproceso e iniciando otro lo suficientemente rápido como para que parezca que se está ejecutando al mismo tiempo. Esto es como Python con el GIL: solo un hilo se está ejecutando realmente.

El problema es que el hilo se puede suspender en cualquier lugar, por ejemplo, si quiero calcular b = (a + b) * 3, esto podría producir instrucciones algo como esto:

1    a += b
2    a *= 3
3    b = a

Now, lets say that is running in a thread and that thread is suspended after either line 1 or 2 and then another thread kicks in and runs:

b = 5

Then when the other thread resumes, b is overwritten by the old computed values, which is probably not what was expected.

So you can see that even though they’re not ACTUALLY running at the same time, you still need locking.

Deja un comentario