perf_counter_ns: mide rendimiento en nanosegundos

Publicado el: 20/09/2026
Tempo de leitura: 4 minutos
Código Python medido para analizar rendimiento con perf_counter_ns

Medir el tiempo de ejecución parece sencillo, pero pequeños errores de método pueden producir benchmarks engañosos. El módulo time de Python ofrece perf_counter_ns(), un reloj de alto rendimiento que devuelve enteros en nanosegundos. Es útil para comparar operaciones cortas, registrar latencias y evitar pérdidas de precisión por punto flotante en series largas. En esta guía aprenderás a usarlo correctamente, interpretar sus resultados y crear mediciones más confiables.

Qué devuelve perf_counter_ns

time.perf_counter_ns() devuelve el valor actual de un contador de rendimiento en nanosegundos. El número absoluto no representa una fecha. Solo tiene sentido cuando se compara con otra lectura del mismo contador.

from time import perf_counter_ns

inicio = perf_counter_ns()
resultado = sum(i * i for i in range(100_000))
fin = perf_counter_ns()

print(f"Duración: {fin - inicio} ns")

El contador incluye el tiempo transcurrido mientras el proceso espera, por lo que mide latencia total. Python utiliza el reloj de rendimiento de mayor resolución disponible en la plataforma.

Diferencia con perf_counter

perf_counter() devuelve segundos como número de punto flotante. perf_counter_ns() devuelve nanosegundos como entero. Ambas funciones usan el mismo reloj, pero la versión en nanosegundos evita conversiones y redondeos acumulados.

El nombre no garantiza una resolución física de un nanosegundo. La resolución real depende del sistema operativo y del hardware. El sufijo indica la unidad y el tipo entero del resultado.

Convertir a unidades legibles

duracion_ns = fin - inicio
microsegundos = duracion_ns / 1_000
milisegundos = duracion_ns / 1_000_000
segundos = duracion_ns / 1_000_000_000

Conviene conservar el entero original durante los cálculos y convertirlo solo al mostrar o exportar los datos.

Una función reutilizable

from time import perf_counter_ns
from collections.abc import Callable
from typing import TypeVar

T = TypeVar("T")

def medir(funcion: Callable[[], T]) -> tuple[T, int]:
    inicio = perf_counter_ns()
    resultado = funcion()
    duracion = perf_counter_ns() - inicio
    return resultado, duracion

resultado, duracion = medir(lambda: sorted(range(50_000), reverse=True))
print(resultado[:3], duracion)

Además de la duración, registra el tamaño de entrada, la versión de Python, la plataforma y el número de repetición.

Medir bloques con un context manager

from contextlib import contextmanager
from time import perf_counter_ns

@contextmanager
def cronometro(etiqueta: str):
    inicio = perf_counter_ns()
    try:
        yield
    finally:
        duracion = perf_counter_ns() - inicio
        print(f"{etiqueta}: {duracion / 1_000_000:.3f} ms")

with cronometro("procesamiento"):
    valores = [x ** 2 for x in range(200_000)]

El bloque finally registra la duración incluso si ocurre una excepción.

Por qué una sola medición no basta

El sistema operativo planifica procesos, las cachés se calientan, el recolector de basura puede ejecutarse y otros programas compiten por recursos. Una sola muestra puede capturar ruido. Repite la operación y analiza la distribución.

from statistics import median
from time import perf_counter_ns

muestras = []
for _ in range(30):
    inicio = perf_counter_ns()
    sum(range(100_000))
    muestras.append(perf_counter_ns() - inicio)

print("mediana:", median(muestras), "ns")
print("mínimo:", min(muestras), "ns")

La mediana suele representar mejor la ejecución típica cuando existen picos. El mínimo puede aproximar el coste sin interrupciones, pero no siempre representa producción.

Warm-up y cachés

La primera ejecución puede pagar importaciones, creación de objetos, lecturas de disco, resolución DNS o inicialización de cachés.

def tarea():
    return sum(i * i for i in range(20_000))

for _ in range(5):
    tarea()

No ocultes el coste de arranque cuando forme parte de la experiencia del usuario.

Cuándo usar timeit

Para microbenchmarks, timeit suele ser más seguro porque repite la operación y ofrece una interfaz específica. perf_counter_ns() es excelente para instrumentar flujos reales, medir tareas asíncronas, registrar latencia y crear métricas personalizadas.

Consulta también medición con timeit, optimización en Python, profiling con cProfile y logging en Python.

Operaciones asíncronas

import asyncio
from time import perf_counter_ns

async def main():
    inicio = perf_counter_ns()
    await asyncio.sleep(0.05)
    duracion = perf_counter_ns() - inicio
    print(duracion / 1_000_000, "ms")

asyncio.run(main())

La duración incluye la espera, lo cual es correcto para latencia de extremo a extremo. Para medir CPU, considera process_time_ns().

Elegir el reloj correcto

time_ns() representa tiempo de calendario y puede ajustarse. monotonic_ns() no retrocede y sirve para intervalos. perf_counter_ns() también es monotónico y usa un contador de alto rendimiento. process_time_ns() mide CPU consumida por el proceso y excluye espera o suspensión.

Errores frecuentes

No compares valores absolutos de máquinas diferentes ni después de reinicios. No interpretes el número como timestamp. Evita incluir impresión, logging, creación de datos o configuración no relacionada dentro del bloque medido.

Tampoco saques conclusiones de diferencias mínimas con pocas muestras. Utiliza entradas realistas, repite las pruebas y registra la variación. El rendimiento depende de datos, cachés, almacenamiento, red, concurrencia, compilación de Python y hardware.

Percentiles de latencia

Los promedios de producción pueden ocultar colas lentas. Guarda muchas duraciones y calcula percentiles como p50, p95 y p99. Una API puede tener una media baja y aun así perjudicar a parte de los usuarios. Conserva valores en nanosegundos o conviértelos a milisegundos para tu sistema de métricas.

Buenas prácticas

Define claramente el inicio y el final de la operación. Haz calentamiento solo cuando corresponda. Usa múltiples repeticiones y datos representativos. Separa tiempo de CPU de latencia total. Compara en el mismo entorno y registra versiones. Antes de optimizar, perfila para localizar un cuello de botella real.

La referencia principal es la documentación oficial de time. Para microbenchmarks controlados, consulta la documentación de timeit.

Conclusión

perf_counter_ns() es una herramienta sencilla y potente para medir duraciones con enteros y alta resolución. Funciona bien para instrumentación, latencia, context managers y pruebas personalizadas. Sin embargo, la confiabilidad depende más del método que de la precisión del reloj. Repite, controla el entorno, usa cargas realistas, elige estadísticas adecuadas y documenta qué incluye cada intervalo. Así, los nanosegundos se convierten en decisiones de optimización mucho más seguras.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Código Python que representa una cola de prioridad con heapq max-heap
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    heapq max-heap: colas de prioridad máxima

    Aprende las funciones max-heap de heapq para colas de prioridad, rankings, planificadores y algoritmos eficientes en Python.

    Ler mais

    Tempo de leitura: 5 minutos
    19/09/2026
    Servidores que representan workers paralelos de ProcessPoolExecutor
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ProcessPoolExecutor kill_workers: detén procesos

    Aprende terminate_workers y kill_workers en ProcessPoolExecutor para detener procesos bloqueados y gestionar futures pendientes con seguridad.

    Ler mais

    Tempo de leitura: 6 minutos
    19/09/2026
    Terminal de línea de comandos usado por una aplicación Python con argparse
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    argparse suggest_on_error: mejora errores de CLI

    Aprende argparse suggest_on_error en Python para recomendar opciones válidas, mejorar errores de CLI y mantener una validación segura.

    Ler mais

    Tempo de leitura: 5 minutos
    18/09/2026
    Código y estructura de archivos para compresión Zstandard en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    compression.zstd: comprime datos con Zstandard

    Aprende a comprimir y descomprimir datos con compression.zstd en Python mediante streams, diccionarios, límites y flujos seguros.

    Ler mais

    Tempo de leitura: 5 minutos
    18/09/2026
    Programador gestionando una cola asíncrona con asyncio.Queue.shutdown
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    asyncio.Queue.shutdown: cierra colas sin deadlocks

    Aprende asyncio.Queue.shutdown en Python para cerrar colas, liberar workers, procesar tareas pendientes y evitar deadlocks.

    Ler mais

    Tempo de leitura: 5 minutos
    17/09/2026
    Depuración de un proceso Python en ejecución con pdb -p
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pdb -p en Python: depura procesos

    Aprende a usar pdb -p en Python para adjuntar el depurador a procesos en ejecución, inspeccionar pilas y diagnosticar bloqueos

    Ler mais

    Tempo de leitura: 6 minutos
    17/09/2026