Saltar al contenido

¿Qué hace exactamente Runtime.Gosched?

Solución:

Nota:

A partir de Go 1.5, GOMAXPROCS se establece en el número de núcleos del hardware: golang.org/doc/go1.5#runtime, debajo de la respuesta original antes de 1.5.


Cuando ejecuta el programa Go sin especificar la variable de entorno GOMAXPROCS, las rutinas Go gor están programadas para su ejecución en un solo hilo del sistema operativo. Sin embargo, para hacer que el programa parezca ser multiproceso (para eso son las goroutines, ¿no?), El planificador de Go a veces debe cambiar el contexto de ejecución, por lo que cada goroutine podría hacer su trabajo.

Como dije, cuando no se especifica la variable GOMAXPROCS, el tiempo de ejecución de Go solo puede usar un hilo, por lo que es imposible cambiar los contextos de ejecución mientras goroutine está realizando algún trabajo convencional, como cálculos o incluso IO (que se asigna a funciones C simples ). El contexto se puede cambiar solo cuando se usan primitivas de concurrencia de Go, por ejemplo, cuando enciende varios canales, o (este es su caso) cuando le dice explícitamente al programador que cambie los contextos; esto es lo que runtime.Gosched es para.

Entonces, en resumen, cuando el contexto de ejecución en una goroutine alcanza Gosched llamada, se indica al planificador que cambie la ejecución a otra goroutine. En su caso hay dos goroutines, main (que representa el hilo ‘principal’ del programa) y adicional, la que ha creado con go say. Si quitas Gosched llamada, el contexto de ejecución nunca se transferirá de la primera goroutine a la segunda, por lo tanto, no hay ‘mundo’ para usted. Cuando Gosched está presente, el planificador transfiere la ejecución en cada iteración de bucle desde la primera goroutine a la segunda y viceversa, por lo que tiene ‘hola’ y ‘mundo’ intercalados.

Para su información, esto se denomina “multitarea cooperativa”: las gorutinas deben ceder explícitamente el control a otras gorutinas. El enfoque utilizado en la mayoría de los sistemas operativos contemporáneos se denomina “multitarea preventiva”: los subprocesos de ejecución no se preocupan por la transferencia de control; en su lugar, el planificador cambia los contextos de ejecución de forma transparente. El enfoque cooperativo se usa con frecuencia para implementar ‘subprocesos verdes’, es decir, corrutinas lógicas simultáneas que no se asignan 1: 1 a subprocesos del sistema operativo; así es como se implementan el tiempo de ejecución de Go y sus goroutines.

Actualizar

Mencioné la variable de entorno GOMAXPROCS pero no expliqué qué es. Es hora de arreglar esto.

Cuando esta variable se establece en un número positivo N, Go runtime podrá crear hasta N subprocesos nativos, en los que se programarán todos los subprocesos verdes. Hilo nativo un tipo de hilo que es creado por el sistema operativo (subprocesos de Windows, pthreads, etc.). Esto significa que si N es mayor que 1, es posible que goroutines se programen para ejecutarse en diferentes subprocesos nativos y, en consecuencia, se ejecuten en paralelo (al menos, hasta las capacidades de su computadora: si su sistema está basado en un procesador multinúcleo, es probable que estos los subprocesos serán realmente paralelos; si su procesador tiene un solo núcleo, entonces la multitarea preventiva implementada en los subprocesos del sistema operativo creará una visibilidad de ejecución paralela).

Es posible configurar la variable GOMAXPROCS usando runtime.GOMAXPROCS() función en lugar de preestablecer la variable de entorno. Use algo como esto en su programa en lugar del actual main:

func main() {
    runtime.GOMAXPROCS(2)
    go say("world")
    say("hello")
}

En este caso puedes observar resultados interesantes. Es posible que obtenga las líneas ‘hola’ y ‘mundo’ impresas intercaladas de manera desigual, p. Ej.

hello
hello
world
hello
world
world
...

Esto puede suceder si las gorutinas están programadas para separar los subprocesos del sistema operativo. De hecho, así es como funciona la multitarea preventiva (o el procesamiento paralelo en el caso de sistemas multinúcleo): los hilos son paralelos y su salida combinada es indeterminista. Por cierto, puedes dejar o quitar Gosched llamada, parece no tener ningún efecto cuando GOMAXPROCS es mayor que 1.

Lo siguiente es lo que obtuve en varias ejecuciones del programa con runtime.GOMAXPROCS llama.

hyperplex /tmp % go run test.go
hello
hello
hello
world
hello
world
hello
world
hyperplex /tmp % go run test.go
hello
world
hello
world
hello
world
hello
world
hello
world
hyperplex /tmp % go run test.go
hello
hello
hello
hello
hello
hyperplex /tmp % go run test.go
hello
world
hello
world
hello
world
hello
world
hello
world

Mira, a veces la salida es bonita, a veces no. Indeterminismo en acción 🙂

Otra actualización

Parece que en las versiones más recientes del compilador Go, el tiempo de ejecución de Go obliga a las goroutines a ceder no solo en el uso de primitivas de concurrencia, sino también en las llamadas al sistema operativo. Esto significa que el contexto de ejecución se puede cambiar entre goroutines también en llamadas de funciones IO. En consecuencia, en los compiladores de Go recientes es posible observar un comportamiento indeterminista incluso cuando GOMAXPROCS no está configurado o configurado en 1.

La programación cooperativa es la culpable. Sin ceder, la otra goroutine (digamos “mundo”) puede tener legalmente cero oportunidades de ejecutarse antes / cuando finalice main, lo que por especificación termina todas las gorutines, es decir. Todo el proceso.

¡Haz clic para puntuar esta entrada!
(Votos: 1 Promedio: 4)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *