Estoy bastante interesado en la función time.sleep de Python. ¿Está usando el reloj del sistema o realmente está contando el ciclo?

Python y sus rutinas de biblioteca estándar son de código abierto. Por lo tanto, es muy fácil investigar este tipo de cosas para ver cómo se hace exactamente. Comencé con una búsqueda en Google para:

código fuente python time.sleep

y de los resúmenes de las páginas mejor clasificadas en los resultados de búsqueda, aprendí que el módulo fuente que tenía el código relevante está en timemodule.c. Entonces mi siguiente búsqueda fue por:

python timemodule.c

y el resultado de búsqueda mejor clasificado me indicó:

python / cpython

Había muchas líneas en ese código fuente, así que busqué “dormir” dentro de la fuente usando el ctl-F de mi navegador. pysleep (línea 1417) parece ser el lugar correcto. Se implementa llamando al servicio de “suspensión” del sistema, por lo que Python no está haciendo una espera ocupada. El único bucle que veo en pysleep es cubrir la posibilidad de una interrupción que despierte el programa demasiado pronto, en cuyo caso presiona el botón de repetición y vuelve a dormir durante el tiempo restante. ¿No odias cuando suena el teléfono antes de que suene la alarma? Sé lo que hago.

La llamada al sistema de suspensión se documenta aquí: suspensión (3): suspensión durante un número específico de segundos. Las páginas man de Linux están organizadas como las páginas man tradicionales de Unix. la sección 1 documenta los comandos, la sección 3 documenta las funciones de la biblioteca C. De ahí el sueño (3). También hay una página de suspensión (1) porque hay un comando de suspensión para usar en los scripts de shell, pero timemodule.c está escrito en C, por lo que cuando llama a la suspensión (…) llama a la función de biblioteca C. Si está muy interesado en cómo funciona, gcc y su biblioteca también son de código abierto y puede buscar exactamente cómo se implementa. Estoy bastante seguro de que lo encontrará principalmente solo por un servicio del sistema. Si está hablando de un sistema Linux, Linux también es de código abierto y puede profundizar en el kernel para ver exactamente cómo funciona. en algún momento puede que tenga que leer sobre cómo los chips de hardware implementan interrupciones. pero quizás antes de llegar tan lejos decidas que ahora lo entiendes lo suficientemente bien como para usarlo. O, si está utilizando Windows, obtendrá una comprensión de la distinción entre código abierto y código cerrado. Si está de acuerdo con sus términos, Microsoft podría incluso permitirle mirar su código fuente, pero tenga cuidado. Es muy probable que aceptes no volver a escribir ningún código funcionalmente similar en tu carrera. Verdaderamente un trato con el diablo si alguna vez hubo uno.

Páginas de manual de Unix en la sección 2 llamadas al sistema de documentos. Por lo tanto, hay una página de manual “sleep (2)” que documenta la llamada al sistema que espero que encuentre en el código fuente de la función de biblioteca C que está documentada en la página de manual “sleep (3)”. Todo se puede conocer, pero hay mucho que saber …

Espero que eso ayude.

Si 🙂

Primero, hablemos del reloj de tiempo real (RTC). Esta es una pequeña pieza de hardware en su placa base, alimentada por esa batería de reloj que ve cuando abre su computadora:


Simplemente mantiene un contador y lo actualiza de vez en cuando. El tiempo que realmente se muestra en el escritorio de su computadora es un trabajo del sistema operativo; en función de lo que sabe sobre las zonas horarias, el horario de verano y otras cosas, restará un número del número informado por el RTC y convertirá el resultado a una fecha y hora Entonces, como puede ver, algunos cambios ni siquiera requieren configurar realmente el reloj; es posible que haya notado esto si tiene un arranque dual, porque la hora mostrada puede ser incorrecta en un sistema operativo y correcta en el otro (ver cómo el hardware es solo informar el valor del contador, y depende del sistema operativo descubrir cómo mostrar esto).

Sin embargo, esto no es lo que sucedería en su pregunta: cuando configura la hora, no la zona horaria, hay una actualización real del valor del RTC.

Pero time.sleep no usa el reloj de tiempo real: usa el reloj del sistema, un temporizador de intervalo programable. El reloj del sistema es parte de su procesador (más precisamente, el controlador de interrupción programable avanzado, o APIC). Esto funciona internamente al realizar un seguimiento de los ciclos de la CPU y aumentar las solicitudes de interrupción (IRQ) a intervalos programables. Los IRQ hacen exactamente lo que dice su nombre: interrumpen cualquier código que el procesador esté ejecutando actualmente, guardan su estado y pasan el control a un fragmento de código en el sistema operativo. El sistema operativo mantendrá una tabla de tiempos de espera (por varias razones como la de su pregunta y también multitarea, donde los diferentes hilos deberían tener un pequeño intervalo de tiempo para ejecutarse, y ninguno de ellos debería ser capaz de usurpar por completo CPU), y disminuir los activos en cada IRQ. Cuando uno de ellos llegue a cero, ejecutará algún código predefinido, en su caso, uno que active su proceso, para que pueda continuar ejecutándose. Más aquí – Temporizadores.

Pero, ¿cómo se durmió tu proceso de todos modos? Si revisa el código fuente del módulo de time (python / cpython), notará que solo está llamando a select en Linux (y compatibles) y WaitForSingleObjectEx en Windows. Ambos se usan normalmente para E / S, entre otras cosas. Cuando llame a uno de ellos de forma bloqueada, el sistema operativo notará que no desea hacer nada más hasta que esos datos estén disponibles o el período de tiempo de espera haya expirado, y lo pondrá a dormir mientras funciona (poner a dormir = estado de subprocesos configurados como “inactivos”, por lo que cuando llegue el momento de decidir quién corre a continuación, sus subprocesos quedan descalificados). Cuando termine (los datos están disponibles o transcurrió el tiempo de espera, lo que ocurra primero), reanudará su proceso, y desde su punto de vista no transcurrió el tiempo, esta fue solo una llamada de función normal 🙂

Espero que esto explique por qué la respuesta es “sí”: está usando el reloj del sistema (no debe confundirse con el reloj de tiempo real, que es probablemente lo que quiso decir cuando dijo “reloj del sistema”), y el reloj del sistema está contando bucles (y convertirlos a microsegundos usando la frecuencia de CPU actual), pero lo está haciendo internamente y en hardware real, no en software 🙂

PD Existe cierta interacción entre el reloj de tiempo real y el temporizador de intervalo programable: el RTC se llama así porque mantiene el “tiempo real”, es decir, el tiempo del reloj de pared, pero esto requeriría muchos bits para ser preciso, mientras que el PIT es solo mantener un contador desde la última vez que se encendió la computadora (y, por lo tanto, puede permitirse ser mucho más preciso). Normalmente, cuando se inicia su sistema operativo, obtendrá el valor del RTC, pero proceda a actualizarlo solo desde el PIT más preciso. Cuando se apaga, guardará el nuevo valor nuevamente en el RTC, para que se mantenga mientras la computadora está apagada.

PPS Lo que sugirió inicialmente, es decir, un bucle simple en el software, se llama “espera ocupada” o “bucle ocupado”, porque consume recursos de la CPU mientras lo hace, pero en realidad puede ser mejor si necesita intervalos muy cortos de esperar, porque no incurre en la sobrecarga de llamar al sistema operativo, desprogramar su subproceso, luego esperar a ser programado nuevamente … Sin embargo, si necesita dormir durante segundos (en lugar de microsegundos o milisegundos), esto fijará el CPU al 100% de uso durante demasiado tiempo.

Veamos cómo time.sleep interactúa con el sistema operativo cuando se ejecuta en Linux:

$ strace -f python3 -c ‘tiempo de importación; time.sleep (3) ‘

select (0, NULL, NULL, NULL, {3, 0}) = 0 (Tiempo de espera)

Aquí vemos que usa la selección de llamada del sistema. Es parte del estándar POSIX y depende de cada sistema operativo cómo se implementa.

Página de manual de POSIX select: select (3): multiplexación síncrona de E / S

Página de manual de select específica de Linux: select (2): multiplexación de E / S síncrona

Para más detalles sobre Linux select: Programación de red: ¿Cómo se implementa select? Hay un enlace al código fuente si está interesado.

Creo que usa algún tipo de reloj de hardware (hay varios tipos), pero estos relojes solo “cuentan”, no es un reloj de pared con ajuste de hora, DST, etc., por lo que cualquier ajuste de hora no cambiará la duración de la selección ( ), time.sleep () etc. Esto es lógico (de lo contrario, muchas cosas estarían rotas) pero no pude encontrar ninguna referencia confiable sobre esto para vincular aquí.