LibXev est une boucle d'événement multiplateforme. LIBXEV fournit une abstraction de boucle d'événements unifiée pour les IO non bloquantes, les minuteries, les signaux, les événements, et plus encore qui fonctionne sur macOS, Windows, Linux et WebAssembly (Browser et Wasi). Il est écrit en zig mais exporte une API compatible C (ce qui le rend compatible avec n'importe quelle langue qui peut communiquer avec les API C).
État du projet :? Qualité instable et alpha-ish. La liste des fonctionnalités est assez bonne sur plusieurs plates-formes, mais il existe de nombreuses fonctionnalités manquantes. Le projet n'a pas été bien testé dans des environnements du monde réel et il y a beaucoup de fruits à faible collecte pour l'optimisation des performances. Je ne promet aucune compatibilité API à ce stade non plus. Si vous voulez une production de production, de haute qualité et de mise en œuvre de boucle d'événements généralisée, consultez Libuv, Libev, etc.
Pourquoi une nouvelle bibliothèque en boucle d'événements? Quelques raisons. Premièrement, je pense que Zig n'a pas une boucle d'événements généralisée comparable à Libuv dans les fonctionnalités («généralisé» étant un mot clé ici). Deuxièmement, je voulais construire une bibliothèque comme celle-ci autour des modèles de conception de IO_URING, imitant même son style en plus d'autres primitives du système d'exploitation (crédit à cet article de blog génial). Troisièmement, je voulais une bibliothèque de boucle d'événements qui pourrait construire sur WebAssembly (à la fois Wasi et autoportant) et qui ne s'intègre pas vraiment bien dans les objectifs du style API des bibliothèques existantes sans apporter quelque chose de super lourd comme Emscripten. La motivation de cette bibliothèque, cependant, me gratte les démangeaisons!
Multiplateforme. Linux ( io_uring et epoll ), MacOS ( kqueue ), WebAssembly + WASI ( poll_oneoff , filed et non threadried Runtime). (La prise en charge de Windows est prévue et à venir bientôt)
API proacteur. Les travaux sont soumis à la boucle d'événement LibXev et l'appelant est informé de l'achèvement du travail, par opposition à la préparation au travail.
Attributions de l'exécution zéro. Cela permet de rendre les performances d'exécution plus prévisibles et rend le libxev bien adapté aux environnements intégrés.
THIMERS, TCP, UDP, fichiers, processus. API à plate-forme de haut niveau pour interagir avec les minuteries, les prises TCP / UDP, les fichiers, les processus, etc. Pour les plates-formes qui ne prennent pas en charge Async IO, les opérations de fichiers sont automatiquement planifiées dans un pool de threads.
Pool de filetage générique (facultatif). Vous pouvez créer un pool de threads génériques, configurer son utilisation des ressources et l'utiliser pour effectuer des tâches d'arrière-plan personnalisées. Le pool de threads est utilisé par certains backends pour effectuer des tâches non bloquantes qui n'ont pas d'API non bloquantes fiables (comme les opérations de fichiers locales avec kqueue ). Le pool de threads peut être partagé sur plusieurs threads et boucles d'événements pour optimiser l'utilisation des ressources.
API de bas niveau et de haut niveau. L'API de haut niveau est agnostique à la plate-forme mais a un comportement d'opinion et une flexibilité limitée. L'API de haut niveau est recommandée mais l'API de bas niveau est toujours une trappe d'évacuation disponible. L'API de bas niveau est spécifique à la plate-forme et fournit un mécanisme aux utilisateurs de LiBXEV pour éliminer les performances maximales. L'API de bas niveau est juste une abstraction suffisante au-dessus de l'interface OS pour le rendre plus facile à utiliser sans sacrifier des performances notables.
Treatage d'arbre (zig). Il s'agit d'une caractéristique de Zig, mais profite substantiellement aux bibliothèques telles que LibXev. Zig n'inclura que les appels de fonction et les fonctionnalités que vous utilisez réellement. Si vous n'utilisez pas de type d'observateur de haut niveau (comme les prises UDP), la fonctionnalité liée à cette abstraction n'est pas du tout compilée dans votre binaire final. Cela permet à LibXev de prendre en charge les fonctionnalités "sympas" facultatives qui peuvent être considérées comme "Bloat" dans certains cas, mais l'utilisateur final n'a pas à payer pour cela.
Sans dépendance. LIBXEV n'a pas de dépendances autres que les API OS intégrées lors de l'exécution. La bibliothèque C dépend de LIBC. Cela facilite la compilation très facile.
Il y a beaucoup de fonctionnalités manquantes que je veux toujours ajouter:
Et plus ...
Il y a beaucoup de place pour les améliorations des performances, et je veux être entièrement clair que je n'ai pas fait beaucoup de travail d'optimisation. Pourtant, les performances ont l'air bien. J'ai essayé de porter de nombreux repères Libuv pour utiliser l'API LibXev.
Je ne publierai pas de résultats de référence spécifiques avant d'avoir un meilleur environnement pour les exécuter. En tant que généralisation très large , vous ne devriez pas remarquer un ralentissement en utilisant LiBXEV par rapport aux autres boucles d'événements majeures. Cela peut différer sur une base de fonctionnalités, et si vous pouvez montrer des performances très médiocres dans un numéro, je souhaite le résoudre!
L'exemple ci-dessous montre un programme identique écrit en zig et en C qui utilise libxev pour exécuter une seule minuterie 5s. C'est presque idiot à quel point il est simple, mais il est censé transmettre la sensation globale de la bibliothèque plutôt qu'un cas d'utilisation pratique.
| Zigou | C |
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 ;
} |
Ces instructions concernent uniquement les utilisateurs en aval en zig. Si vous utilisez l'API C vers LiBXEV, consultez la section "Build".
Ce package fonctionne avec le gestionnaire de packages en zig introduit dans Zig 0.11. Créez un fichier build.zig.zon comme ceci:
.{
. name = "my-project" ,
. version = "0.0.0" ,
. dependencies = .{
. libxev = .{
. url = "https://github.com/mitchellh/libxev/archive/<git-ref-here>.tar.gz" ,
. hash = "12208070233b17de6be05e32af096a6760682b48598323234824def41789e993432c" ,
},
},
} Et dans votre build.zig :
const xev = b . dependency ( "libxev" , .{ . target = target , . optimize = optimize });
exe . addModule ( "xev" , xev . module ( "xev" ));? La documentation est un travail en cours. ?
Actuellement, la documentation est disponible sous trois formes: pages d'homme , exemples et commentaires de code. À l'avenir, je prévois d'écrire des guides détaillés et une documentation API sous forme de site Web, mais ce n'est pas actuellement disponible.
Les pages de l'homme sont relativement détaillées! xev(7) vous donnera un bon aperçu de toute la bibliothèque. xev-zig(7) et xev-c(7) fourniront respectivement des aperçus de l'API Zig et C. De là, des pages d'homme API-Specifc telles que xev_loop_init(3) sont disponibles. C'est la meilleure documentation actuellement.
Il existe plusieurs façons de parcourir les pages de l'homme. Le plus immédiatement convivial est de simplement parcourir les sources de page Raw Man dans les docs/ répertoire de votre navigateur Web. La source de la page Man est une syntaxe de type Markdown, donc elle rend correctement dans votre navigateur via GitHub.
Une autre approche consiste à exécuter zig build -Dman-pages et les pages de l'homme seront disponibles en zig-out . Cela nécessite que SCDOC soit installé (ceci est disponible dans la plupart des gestionnaires de packages). Une fois que vous avez construit les pages de l'homme, vous pouvez les rendre par chemin:
$ man zig-out/share/man/man7/xev.7
Et la dernière approche consiste à installer LibXev via votre gestionnaire de packages préféré (si et quand disponible), ce qui devrait, espérons-le, mettre vos pages d'homme dans votre chemin d'homme, afin que vous puissiez simplement faire man 7 xev .
Il existe des exemples disponibles dans les examples/ dossiers. Les exemples sont disponibles en C et en zig, et vous pouvez dire lequel est lequel utilisant l'extension de fichier.
Pour créer un exemple, utilisez ce qui suit:
$ zig build -Dexample-name=_basic.zig
...
$ zig-out/bin/example-basic
...
La valeur -Dexample-name doit être le nom de fichier, y compris l'extension.
Le code en zig est bien commenté. Si vous êtes à l'aise de lire des commentaires de code, vous pouvez trouver beaucoup de perspicacité en eux. La source est dans le répertoire src/ .
Build nécessite l'installation du dernier zig tous les soirs. libxev n'a pas d'autres dépendances de construction.
Une fois installé, zig build install à lui-même construira la bibliothèque complète et sortira un répertoire compatible FHS en zig-out . Vous pouvez personnaliser le répertoire de sortie avec l'indicateur --prefix .
LibXev possède une grande suite d'essai. Pour exécuter les tests pour la plate-forme actuelle:
$ zig build test
...Cela exécutera tous les tests pour toutes les fonctionnalités prises en charge pour la plate-forme hôte actuelle. Par exemple, sur Linux, cela exécutera à la fois la suite complète IO_URING et EPOLL.
Vous pouvez créer et exécuter des tests pour d'autres plates-formes en compilant transversal l'exécutable de test, en le copie sur une machine cible et en l'exécutant. Par exemple, ce qui est ci-dessous montre comment croiser et construire les tests pour macOS à partir 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 est un cas spécial. Vous pouvez exécuter des tests pour Wasi si vous avez été installé:
$ zig build test -Dtarget=wasm32-wasi -Dwasmtime
...