1 puntos por GN⁺ 2 시간 전 | 1 comentarios | Compartir por WhatsApp
  • El interior de zig build ahora se divide en procesos de configurador y creador, y el grafo de compilación generado por build.zig se serializa como un archivo de configuración binario
  • El proceso padre almacena en caché el archivo de configuración y compila al creador en modo Release de forma asíncrona; el creador se compila solo una vez en la caché global por cada versión de Zig
  • Cuando el usuario modifica build.zig, ya no se compila junto con él todo el sistema de compilación, lo que reduce el costo en tiempo de añadir funciones como --watch, --fuzz y --webui
  • El tiempo promedio de ejecución de zig build --help bajó de 150ms a 14.3ms, y los ciclos de CPU, la cantidad de instrucciones y las referencias de caché también se redujeron entre 94% y 96%
  • La mayoría de las API siguen siendo compatibles, pero la observación directa de b.args se reemplaza por addPassthruArgs(), y Zig 0.17.0 está previsto para dentro de unas semanas

Cambio en la arquitectura del sistema de compilación

  • Se fusionó una rama grande, separando el interior de zig build en un proceso configurador y un proceso creador
  • En la estructura anterior, el archivo build.zig y toda la implementación del sistema de compilación se compilaban como un único proceso grande en modo Debug, y build.zig construía el grafo de compilación en memoria antes de que el “build runner” lo ejecutara
  • En la nueva estructura, build.zig se compila como un pequeño proceso configurador en modo Debug, y el grafo de compilación se serializa como un archivo de configuración binario
  • El proceso padre zig build detecta el archivo de configuración, lo guarda en caché para la siguiente ejecución y compila de forma asíncrona en modo Release al creador encargado de ejecutar el grafo de compilación
  • Cuando el archivo de configuración y la compilación del creador están listos, el creador recibe el archivo y se ejecuta; gracias a la caché global, el creador solo necesita compilarse una vez por cada zig version

Efectos en la mejora de velocidad

  • El objetivo principal es mejorar la velocidad de zig build, y al cambiar build.zig del usuario ya no se recompila junto con él todo el sistema de compilación
  • Esto cobra más importancia porque, aunque se agreguen más funciones al sistema de compilación con --watch, --fuzz y --webui, el tiempo de zig build ya no crecerá junto con ellas
  • Si se determina que no hubo cambios, se puede reutilizar la configuración anterior sin volver a ejecutar la lógica de build.zig
  • Por ejemplo, aunque se agregue -freference-trace a la línea de comandos de zig build, no hace falta volver a ejecutar innecesariamente la lógica de build.zig
  • Como el proceso que ejecuta el grafo de compilación real se compila con optimizaciones activadas, la etapa de ejecución también es más rápida

Resultados de benchmark

  • El tiempo promedio de ejecución de zig build --help se redujo de 150ms en la estructura anterior a 14.3ms en la nueva
  • El tiempo de reloj de pared bajó de 150ms a 14.3ms, una reducción de 90.4%, y los ciclos de CPU pasaron de 593M a 24.1M, una reducción de 95.9%
  • La cantidad de instrucciones cayó de 995M a 43.7M, una reducción de 95.6%, y las referencias de caché bajaron de 25.8M a 1.46M, una reducción de 94.3%
  • El RSS máximo se redujo de 84.8MB a 78.5MB, una reducción de 7.4%
  • La mayor diferencia proviene del cambio desde un enfoque que ejecutaba la lógica de build.zig en cada comando zig build a otro que reutiliza una configuración serializada almacenada en caché

Impacto en herramientas y compatibilidad

  • Las herramientas de terceros como ZLS pueden beneficiarse al consumir el archivo de configuración serializado en lugar de seguir manteniendo una bifurcación del build runner
  • Aunque los mecanismos internos cambiaron mucho, desde el punto de vista de la API se mantiene en su mayor parte la compatibilidad
  • Las excepciones corresponden a los cambios resumidos en el PR fusionado

Principales cambios incompatibles

  • El cambio con más probabilidad de afectar a muchos usuarios es la eliminación del patrón que observaba directamente b.args
  • Código anterior:
if (b.args) |args| {
    run_cmd.addArgs(args);
}
  • Código nuevo:
run_cmd.addPassthruArgs();
  • Con este cambio, los scripts de compilación ya no pueden observar esos argumentos, por lo que se elimina una funcionalidad
  • A cambio, cambiar esos argumentos ya no obliga a recompilar el script de compilación desde el código fuente

Pruebas y calendario de lanzamiento

  • Los usuarios que quieran influir en la dirección de Zig pueden actualizar sus proyectos a la versión de desarrollo para probar los cambios nuevos y dar retroalimentación
  • Zig 0.17.0 está previsto para lanzarse dentro de unas semanas
  • Como no hubo tiempo para probarlo de antemano, incluso si alguna compilación se rompe en 0.17.0, todavía habrá suficiente oportunidad para incluir correcciones en la etiqueta 0.17.1

1 comentarios

 
GN⁺ 2 시간 전
Comentarios en Hacker News
  • Probé migrar parte de mi código a Zig 0.16.0 y el resultado me dejó bastante satisfecho
    Aunque hubo muchísimas partes afectadas, los cambios en sí fueron buenos y parecen ir en una dirección que hace ver prometedor el futuro del lenguaje
    En particular, el nuevo mecanismo de entrada/salida permite código eficiente con una forma elegante tanto en implementaciones de un solo hilo como de varios hilos y bucles de eventos
    Si todavía no has usado Zig desde la 0.16.0, vale la pena echarle un vistazo. Las notas de esta versión fueron larguísimas
    https://ziglang.org/download/0.16.0/release-notes.html

    • Todavía no diría que es “muy eficiente”. Io sigue siendo despacho dinámico y hay varios niveles de indirección
      Hasta donde sé, es más lento que antes
      Espero que en las próximas versiones resuelvan el problema de que “el destino del despacho se conoce en tiempo de compilación pero sigue siendo dinámico”, para reducir esa pérdida de eficiencia
    • Me costó un poco entender cómo funciona el nuevo mecanismo de entrada/salida, especialmente async/await
      Supongo que cuando llamas a io.async en una implementación de IO basada en un bucle de eventos, internamente inicia algo parecido a una “tarea”, y el future sería su handle
      La parte que no entiendo es cuando se llama a future.await(io). ¿La implementación de IO suspende de algún modo la función actual y luego la reanuda cuando el future se resuelve? Si es así, ¿significa eso que todas las funciones de Zig son corutinas sin pila?
    • Algún día podré usar estas funciones nuevas, pero por estabilidad y por objetivos menos probados termino usando .use_llvm = true en los builds de Zig
  • Después de usar Zig durante unos meses, terminé convencido de que es un excelente lenguaje para herramientas
    Es bueno para tomarlo y armar ideas libremente y de forma improvisada, y en cada punto donde uno se traba suele haber una solución cómoda que quienes lo hicieron ya pensaron
    Pero eso no significa que te obligue a usar el lenguaje de la manera “correcta”
    Ahora se convirtió en mi lenguaje base para “andar cacharreando en el garaje”

    • Decir que no te obliga a usarlo de la manera “correcta” suena discutible, cuando no permite variables sin usar y tampoco tiene comentarios multilínea
      Para mí eso sí es un problema importante de productividad
    • ¿De verdad es tan bueno?
      Mi lenguaje base para “andar cacharreando en el garaje” es Python. Sintaxis ligera, uso sin fricciones, biblioteca estándar abundante, y para lo que no hay, existen paquetes para todo
      ¿Cuál sería la ventaja de Zig?
    • Mi principal traba aquí es que, para mí, Mojo probablemente termine siendo el lenguaje base para experimentar
    • Sin duda es un gran lenguaje para experimentar, pero el equipo y la comunidad de Zig tienen preferencias muy marcadas sobre cómo se debe usar el lenguaje “correctamente”
  • Vi un video de entrevista a Andrew Kelley y me dieron ganas de aprender Zig: https://www.youtube.com/watch?v=iqddnwKF8HQ

    • Respeto mucho a Andrew y también disfruto usar Zig, pero esa entrevista fue terrible
      Las respuestas de Andrew estuvieron bien, pero el ambiente general se sintió demasiado adulador
  • Quería probar Zig, pero el lenguaje todavía cambia demasiado rápido
    En cada lanzamiento rompen APIs, así que me resultó difícil seguir al mismo tiempo el aprendizaje del lenguaje, el debugging del sistema de build y la implementación de lo que realmente quería hacer
    Después de ver la entrevista de JetBrains sí me dieron ganas de intentarlo otra vez, pero probablemente espere hasta que salga la 1.0

  • Desde hace mucho vengo pensando en una idea que llamo programación dual
    Consiste en construir el stack con exactamente dos lenguajes: uno de alto nivel y otro de bajo nivel
    La idea es escribir tanto como sea posible en el lenguaje de alto nivel, y bajar al de bajo nivel solo cuando haga falta
    El problema es que, si no conoces ya muy bien el lenguaje de bajo nivel, es muy probable que tengas que volver a familiarizarte con él antes de hacer trabajo de bajo nivel
    Por eso C++ o Rust se me hacen más difíciles de retomar que C, y C termina siendo mi opción por defecto. Pero C también tiene problemas bien conocidos
    Zig parece poder ocupar bien ese punto justo, porque es lo bastante simple como para retomarlo incluso después de una pausa larga, y al mismo tiempo tiene herramientas modernas que facilitan programar

    • La idea es interesante, pero yo pienso al revés
      Intento hacer tanto como sea posible en el lenguaje de bajo nivel, y solo subir al de alto nivel cuando la conveniencia realmente justifica el costo
      Roc hace posible esto. Todos los programas tienen una plataforma escrita en un lenguaje de bajo nivel, y los programas de Roc usan la API que esa plataforma expone
      https://www.roc-lang.org/
      Claro que cómo equilibrar lo de alto y bajo nivel lo puede decidir cada quien
    • Hasta donde sé, SpaCy se desarrolla de esa manera
      Los modelos se implementan en Cython y la API orientada al usuario se ofrece en Python
    • C# está bastante cerca de ese objetivo
    • O simplemente usa un solo lenguaje que haga bien tanto programación de alto nivel como de bajo nivel, como Rust
      Ahora hago todo con Rust y, especialmente gracias a su sistema de tipos al estilo OCaml, todavía no he encontrado nada que no pueda hacer
    • Una combinación muy común para esto era C con Lua
      Lua fue pensado como lenguaje embebido, así que tiene buena interoperabilidad y al mismo tiempo es de alto nivel, por lo que resulta fácil de usar
      Hay una razón por la que Factorio usa Lua como lenguaje de scripting
  • Lo que me gusta del desarrollo de Zig es que, más que añadir funciones al lenguaje, invierten una cantidad sorprendente de esfuerzo en las herramientas y el ciclo de retroalimentación del desarrollador
    Un lenguaje nuevo puede sobrevivir un tiempo aunque le falte alguna función
    Pero si compilar, enlazar y actualizar dependencias se siente lento cada vez, le resulta mucho más difícil sobrevivir
    Ese enfoque en llevar el ciclo de desarrollo no a segundos sino a milisegundos parece una muy buena apuesta a largo plazo

  • Me sorprende leer que “planean lanzar la 0.17.0 en unas semanas”
    ¿La 0.16 no tardó más de un año?
    No esperaba una 0.17 tan rápida, pero me da mucho gusto enterarme hoy

  • Suena como una buena noticia. El tiempo de compilación de Zig ya es excelente, y parece que con este cambio será aún mejor.

    • En mi experiencia, diría que eso todavía está más cerca de ser una meta que una realidad.
      Sin duda es una meta importante, y los hitos sobre cómo alcanzarla están claros, pero en la práctica cuesta llamar “excelente” a la dolorosa espera cuando se compila por primera vez un proyecto vacío o cuando ZLS vuelve a compilarse después de direnv allow.
    • Incluso si creo un archivo con una prueba dummy y ejecuto zig test file.zig -OReleaseSafe, en mi computadora tarda varios segundos.
      Y cada vez que modifico el archivo vuelve a tardar lo mismo. No es que esté usando un toolchain viejo, porque uso 0.16 o master, y además estoy en Linux.
      El lenguaje Zig en sí es realmente muy agradable de usar, pero me parece que el compilador y la biblioteca estándar no se están desarrollando con suficiente conservadurismo.
      Puede que no te topes con estos problemas cuando empiezas con un hello world, pero si quieres hacer fuzz testing o benchmarks, terminas queriendo ejecutar un binario optimizado.
      Y entonces compilar incluso una cantidad relativamente pequeña de código se vuelve demasiado frustrante.
      En comparación, creo que Zig es mucho mejor como lenguaje que Rust/C++/C, pero este tipo de problemas en realidad casi nunca ocurren en Rust/C++/C. En C/C++ asumiendo que usas clang/gcc/ninja, claro.
      En la misma computadora puedo configurar, compilar (-O2 o -O3) y probar un proyecto de C++ de unas 10 mil líneas con Ninja/Python/clang en 200 ms.
    • Por suerte, las velocidades de compilación estilo años 90 están regresando lentamente.
  • Estaría buenísimo que Zig tuviera un mecanismo oficial para exportar stubs de bibliotecas de Linux.
    La compilación cruzada de Zig y su capacidad de apuntar a versiones arbitrarias de glibc son magia pura.
    Estoy aprovechando esa magia en un sistema de build de C++ separado, pero para obtener esos stubs de bibliotecas desde Zig tengo que dar rodeos.
    Sería bueno que se ofrecieran como una salida oficial.

  • ¿Qué motivo habría para querer usar esto en lugar de Node.js y TypeScript?

    • Envidio esa forma de pensar. Si yo hubiera sido así, probablemente ya habría publicado muchas más apps.
    • Te recomendaría probar un rato Ghostty, escrito en Zig, y compararlo con una terminal como Hyper, escrita en JavaScript.
    • ¿No será porque están hechos para dominios totalmente distintos?
    • Si lo que haces encaja bien con Node y TypeScript, diría que no hay motivo para usar Zig más allá del aprendizaje o la curiosidad.
      Si no necesitas exprimir hasta la última gota de rendimiento ni layout y control de memoria, usar Zig tiene más desventajas.
      Para trabajo CRUD, “enterprise” o sitios web, Zig casi no ofrece ventajas.
    • En sistemas embebidos no puedes ejecutar Node porque falta memoria.
      Un programa compilado en Zig puede ocupar apenas unos pocos KB y no tener dependencias.
      El acceso a arreglos escrito en un lenguaje de bajo nivel puede optimizarse con SIMD y paralelización, y puede ser varios órdenes de magnitud más rápido que hacer lo mismo en JavaScript.
      En procesamiento de texto, manipulación de imágenes, procesamiento de video, hashing y más, la diferencia es grande.
      En realidad hay prácticamente infinitas razones para no usar JavaScript.