LibXEV es un bucle de evento multiplataforma. LibXEV proporciona una abstracción de bucle de eventos unificada para IO, temporizadores, señales, eventos y más no bloqueos que funcionan en macOS, Windows, Linux y WebAssembly (navegador y WASI). Está escrito en zig, pero exporta una API compatible con C (que lo hace compatible con cualquier idioma que pueda comunicarse con las API C).
Estado del proyecto :? Calidad inestable, alfa. La lista de características es bastante buena en múltiples plataformas, pero hay muchas características faltantes. El proyecto no se ha probado bien en entornos del mundo real y hay muchas frutas de bajo contenido para la optimización del rendimiento. Tampoco estoy prometiendo ninguna compatibilidad de API en este momento. Si desea una producción, implementación de bucle de eventos de alta calidad y de alta calidad, consulte Libuv, Libev, etc.
¿Por qué una nueva biblioteca de bucle de eventos? Algunas razones. Uno, creo que Zig carece de un bucle de evento generalizado comparable a Libuv en características ("generalizado" es una palabra clave aquí). Dos, quería construir una biblioteca como esta en torno a los patrones de diseño de Io_uring, incluso imitando su estilo además de otras primitivas del sistema operativo (crédito a esta increíble publicación de blog). Tres, quería una biblioteca de bucle de eventos que pudiera construir en WebAssembly (tanto Wasi como independiente) y eso realmente no encajaba bien en los objetivos del estilo API de las bibliotecas existentes sin traer algo súper pesado como Emscripten. ¡La motivación para esta biblioteca principalmente es rascar mi propia picazón!
Platforma cruzada. Linux ( io_uring y epoll ), MacOS ( kqueue ), WebAssembly + WASI ( poll_oneoff , TIGOS DE ENCUENTRO ENCUENTRO Y NO THREADOS). (El soporte de Windows está planeado y próximamente)
API proactor. El trabajo se envía al bucle de eventos libxev y la persona que llama se notifica a la finalización del trabajo, en lugar de la preparación laboral.
Cero asignaciones de tiempo de ejecución. Esto ayuda a que el rendimiento del tiempo de ejecución sea más predecible y hace que LibXEV sea muy adecuado para entornos integrados.
Temporizadores, TCP, UDP, archivos, procesos. API agnósticas de plataforma de alto nivel para interactuar con temporizadores, enchufes TCP/UDP, archivos, procesos y más. Para las plataformas que no admiten Async IO, las operaciones del archivo se programan automáticamente en un grupo de subprocesos.
Grupo de hilo genérico (opcional). Puede crear un grupo de subprocesos genéricos, configurar su utilización de recursos y usarlo para realizar tareas de fondo personalizadas. Algunos backends utilizaron el grupo de subprocesos para realizar tareas que no son de bloqueo que no tengan API confiables sin bloqueo (como operaciones de archivos locales con kqueue ). El grupo de subprocesos se puede compartir en múltiples hilos y bucles de eventos para optimizar la utilización de recursos.
API de bajo nivel y de alto nivel. La API de alto nivel es agnóstica de la plataforma, pero tiene un comportamiento obstinado y una flexibilidad limitada. Se recomienda la API de alto nivel, pero la API de bajo nivel siempre es una escotilla de escape disponible. La API de bajo nivel es específica de la plataforma y proporciona un mecanismo para que los usuarios de LibXEV expriman el máximo rendimiento. La API de bajo nivel es suficiente abstracción por encima de la interfaz del sistema operativo para que sea más fácil de usar sin sacrificar un rendimiento notable.
Trasto de árbol (zig). Esta es una característica de zig, pero sustancialmente beneficia bibliotecas como LibXEV. ZIG solo incluirá llamadas de funciones y características que realmente usa. Si no usa un tipo particular de observador de alto nivel (como enchufes UDP), entonces la funcionalidad relacionada con esa abstracción no se compila en su binario final. Esto permite que LibXEV admite una funcionalidad opcional "agradable de tener" que puede considerarse "hinchazón" en algunos casos, pero el usuario final no tiene que pagarla.
Sin dependencia. Libxev no tiene dependencias más que las API OS incorporadas en tiempo de ejecución. La biblioteca C depende de libc. Esto hace que sea muy fácil compilar.
Hay muchas características faltantes que todavía quiero agregar:
Y más ...
Hay mucho espacio para las mejoras de rendimiento, y quiero ser completamente claro que no he realizado mucho trabajo de optimización. Aún así, el rendimiento se ve bien. He tratado de transferir muchos de los puntos de referencia de Libuv para usar la API de Libxev.
No publicaré resultados de referencia específicos hasta que tenga un mejor entorno para ejecutarlos. Como una generalización muy amplia , no debe notar una desaceleración usando libxev en comparación con otros bucles de eventos importantes. Esto puede diferir en función de la función, y si puede mostrar un rendimiento realmente pobre en un problema, ¡estoy interesado en resolverlo!
El siguiente ejemplo muestra un programa idéntico escrito en zig y en C que usa LibXEV para ejecutar un solo temporizador 5S. Esto es casi tonto lo simple que es, pero está destinado a transmitir la sensación general de la biblioteca en lugar de un caso de uso práctico.
| Zigza | do |
const xev = @import ( "xev" );
pub fn main () ! void {
var loop = try xev . Loop . init (.{});
defer loop . deinit ();
const w = try xev . Timer . init ();
defer w . deinit ();
// 5s timer
var c : xev.Completion = undefined ;
w . run ( & loop , & c , 5000 , void , null , & timerCallback );
try loop . run ( .until_done );
}
fn timerCallback (
userdata : ? * void ,
loop : * xev.Loop ,
c : * xev.Completion ,
result : xev . Timer . RunError ! void ,
) xev.CallbackAction {
_ = userdata ;
_ = loop ;
_ = c ;
_ = result catch unreachable ;
return .disarm ;
} | # include < stddef . h >
# include < stdio . h >
# include < xev . h >
xev_cb_action timerCallback ( xev_loop * loop , xev_completion * c , int result , void * userdata ) {
return XEV_DISARM ;
}
int main ( void ) {
xev_loop loop ;
if ( xev_loop_init ( & loop ) != 0 ) {
printf ( "xev_loop_init failure n " );
return 1 ;
}
xev_watcher w ;
if ( xev_timer_init ( & w ) != 0 ) {
printf ( "xev_timer_init failure n " );
return 1 ;
}
xev_completion c ;
xev_timer_run ( & w , & loop , & c , 5000 , NULL , & timerCallback );
xev_loop_run ( & loop , XEV_RUN_UNTIL_DONE );
xev_timer_deinit ( & w );
xev_loop_deinit ( & loop );
return 0 ;
} |
Estas instrucciones son solo para usuarios de zig aguas abajo. Si está utilizando la API C a Libxev, consulte la sección "Build".
Este paquete funciona con el Manager de paquetes Zig introducido en Zig 0.11. Cree un archivo build.zig.zon como este:
.{
. name = "my-project" ,
. version = "0.0.0" ,
. dependencies = .{
. libxev = .{
. url = "https://github.com/mitchellh/libxev/archive/<git-ref-here>.tar.gz" ,
. hash = "12208070233b17de6be05e32af096a6760682b48598323234824def41789e993432c" ,
},
},
} Y en tu build.zig :
const xev = b . dependency ( "libxev" , .{ . target = target , . optimize = optimize });
exe . addModule ( "xev" , xev . module ( "xev" ));? La documentación es un trabajo en progreso. ?
Actualmente, la documentación está disponible en tres formularios: páginas de hombre , ejemplos y comentarios de código. En el futuro, planeo escribir guías detalladas y documentación de API en el formulario del sitio web, pero eso no está disponible actualmente.
¡Las páginas del hombre son relativamente detalladas! xev(7) le dará una buena descripción de toda la biblioteca. xev-zig(7) y xev-c(7) proporcionarán descripción general de la API ZIG y C, respectivamente. A partir de ahí, están disponibles páginas del hombre API-Specifc como xev_loop_init(3) . Esta es la mejor documentación actualmente.
Hay múltiples formas de navegar por las páginas del hombre. El más amigable de inmediato es navegar por las fuentes de página de Man Raw en los docs/ directorio en su navegador web. La fuente de la página del hombre es una sintaxis similar a Markdown, por lo que funciona bien en su navegador a través de GitHub.
Otro enfoque es ejecutar zig build -Dman-pages y las páginas del hombre estarán disponibles en zig-out . Esto requiere que SCDOC esté instalado (está disponible en la mayoría de los administradores de paquetes). Una vez que haya construido las páginas del hombre, puede renderizarlas por camino:
$ man zig-out/share/man/man7/xev.7
Y el enfoque final es instalar LibXEV a través de su administrador de paquetes favorito (si está disponible y cuándo está disponible), lo que con suerte debería poner sus páginas de hombre en su camino de hombre, para que pueda hacer man 7 xev .
Hay ejemplos disponibles en los examples/ carpeta. Los ejemplos están disponibles en C y ZIG, y puede saber cuál es el uso de la extensión del archivo.
Para construir un ejemplo, use lo siguiente:
$ zig build -Dexample-name=_basic.zig
...
$ zig-out/bin/example-basic
...
El valor -Dexample-name debe ser el nombre de archivo que incluye la extensión.
El código ZIG está bien comentado. Si se siente cómodo leyendo los comentarios del código, puede encontrar mucha información dentro de ellos. La fuente está en el directorio src/ .
Build requiere la instalación de la última noche en zig. LibXEV no tiene otras dependencias de compilación.
Una vez instalado, zig build install por sí sola construirá la biblioteca completa y emitirá un directorio compatible con FHS en zig-out . Puede personalizar el directorio de salida con el indicador --prefix .
LibXEV tiene una suite de prueba grande y en crecimiento. Para ejecutar las pruebas para la plataforma actual:
$ zig build test
...Esto ejecutará todas las pruebas para todas las funciones compatibles para la plataforma de host actual. Por ejemplo, en Linux esto ejecutará la suite de prueba IO_uring y Epoll completa.
Puede construir y ejecutar pruebas para otras plataformas compilando el ejecutable de prueba, copiándolo a una máquina de destino y ejecutándola. Por ejemplo, lo siguiente muestra cómo compilar y construir las pruebas para macOS de Linux:
$ zig build -Dtarget=aarch64-macos -Dinstall-tests
...
$ file zig-out/bin/xev-test
zig-out/bin/xev-test: Mach-O 64-bit arm64 executableWasi es un caso especial. Puede ejecutar pruebas para WASI si ha instalado WASMTIME:
$ zig build test -Dtarget=wasm32-wasi -Dwasmtime
...