¿Hay algunos casos en los hilos de Python puede manipular con seguridad el estado compartidas?

StackOverflow https://stackoverflow.com/questions/2740435

  •  02-10-2019
  •  | 
  •  

Pregunta

Algunas discusiones en otra pregunta me ha animado a entender mejor los casos en que se requiere de bloqueo en programas Python multiproceso.

este artículo el hilo en Python, tengo varios ejemplos sólidos, comprobables de trampas que pueden ocurrir cuando varios subprocesos tienen acceso a estado compartido. La condición ejemplo, la raza proporcionada en esta página implica carreras entre hilos de lectura y manipulación de una variable compartida almacenada en un diccionario. Creo que el caso para una carrera aquí es muy obvio, y afortunadamente es eminentemente comprobable.

Sin embargo, he sido capaz de evocar una condición de carrera con operaciones atómicas tales como los añadidos a la lista o incrementos variables. Esta prueba exhaustivamente los intentos para demostrar una carrera tan:

from threading import Thread, Lock
import operator

def contains_all_ints(l, n):
    l.sort()
    for i in xrange(0, n):
        if l[i] != i:
            return False
    return True

def test(ntests):
    results = []
    threads = []
    def lockless_append(i):
        results.append(i)
    for i in xrange(0, ntests):
        threads.append(Thread(target=lockless_append, args=(i,)))
        threads[i].start()
    for i in xrange(0, ntests):
        threads[i].join()
    if len(results) != ntests or not contains_all_ints(results, ntests):
        return False
    else:
        return True

for i in range(0,100):
    if test(100000):
        print "OK", i
    else:
        print "appending to a list without locks *is* unsafe"
        exit()

He corrido la prueba anterior sin fallo (100x 100k APPENDs multihilo). ¿Alguien puede llegar a fallar? ¿Hay otra clase de objeto que se puede hacer con el mal comportamiento a través atómica, incrementales, modificación por hilos?

¿Estos implícitamente la semántica 'atómicas' se aplican a otras operaciones en Python? Se esta directamente relacionado con el GIL?

¿Fue útil?

Solución

Al añadir a una lista es seguro para subprocesos, sí. Sólo se puede anexar a una lista mientras mantiene el GIL, y la lista se encarga de no liberar el GIL durante la operación append (que es, después de todo, una operación bastante sencilla.) El Para en la cual operaciones de agregación de rosca diferente pasan por supuesto es en juego, pero todos ellos serán serializados operaciones estrictamente debido a que el GIL no se libera durante una anexión.

Lo mismo no es necesariamente cierto para otras operaciones. Una gran cantidad de operaciones en Python pueden causar código Python arbitrario para ser ejecutado, el cual a su vez puede hacer que el GIL para ser lanzado. Por ejemplo, i += 1 es tres operaciones distintas, "llegar i', 'añadir 1 a ella' y 'almacenarla en i'. 'Añadir 1 a la misma' se traduciría (en este caso) en it.__iadd__(1), que puede salir y hacer lo que quiera.

objetos Python mismos guardar su propio estado interno - dicts no corromperse por dos hilos de diferentes artículos que tratan de establecer en ellos. Pero si los datos de la dict se supone que es internamente coherente, ni el dict ni el GIL hace nada para proteger que, salvo (en forma de hilo habitual) por lo que es menos probable pero aún es posible cosas finales hasta diferente de lo que pensaba.

Otros consejos

En CPython, la conmutación de hilo se realiza cuando se ha ejecutado bycodes sys.getcheckinteval (). Por lo que un cambio de contexto no puede ocurrir durante la ejecución de un único código de bytes, y las operaciones que se codifican como un único código de bytes son inherentemente atómica y multi-hilo, a menos que el código de bytes ejecuta otro código Python o llama código C que libera el GIL. La mayoría de las operaciones en el incorporado en los tipos de recolección (dict, lista, etc) caen en la categoría 'inherentemente multi-hilo'.

Sin embargo, este es un detalle de implementación que es específica para la implementación en C de Python, y no debe ser invocado. Otras versiones de Python (Jython, IronPython, PyPy etc.) no pueden comportarse de la misma manera. Tampoco hay ninguna garantía de que las futuras versiones de CPython mantendrán este comportamiento.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top