Je serais intéressé par des aspects comme :
- portée/caractéristiques
- performance
- échéance
Je serais intéressé par des aspects comme :
Boost.Asio est une bibliothèque C++ qui a commencé par se concentrer sur les réseaux, mais ses capacités d'E/S asynchrones ont été étendues à d'autres ressources. De plus, Boost.Asio faisant partie des bibliothèques Boost, son champ d'application est légèrement réduit pour éviter les doublons avec d'autres bibliothèques Boost. Par exemple, Boost.Asio ne fournira pas d'abstraction de threads, comme le fait la bibliothèque Boost.Thread en fournit déjà un.
D'un autre côté, libuv est une bibliothèque C conçue pour être la couche de plateforme pour Node.js . Il fournit une abstraction pour IOCP sur Windows, kqueue sur macOS, et epoll sur Linux. De plus, il semble que son champ d'application se soit légèrement élargi pour inclure des abstractions et des fonctionnalités, telles que les threads, les pools de threads et la communication inter-threads.
Au fond, chaque bibliothèque fournit une boucle d'événements et des capacités d'E/S asynchrones. Elles se chevauchent pour certaines des fonctionnalités de base, comme les timers, les sockets et les opérations asynchrones. libuv a une portée plus large, et fournit des fonctionnalités supplémentaires, comme les abstractions de threads et de synchronisation, les opérations synchrones et asynchrones du système de fichiers, la gestion des processus, etc. En revanche, l'orientation réseau originale de Boost.Asio fait surface, car elle fournit un ensemble plus riche de capacités liées au réseau, telles que ICMP, SSL, des opérations synchrones bloquantes et non bloquantes, et des opérations de plus haut niveau pour les tâches courantes, y compris la lecture d'un flux jusqu'à la réception d'une nouvelle ligne.
Voici une brève comparaison côte à côte de quelques-unes des principales caractéristiques. Puisque les développeurs utilisant Boost.Asio ont souvent d'autres bibliothèques Boost disponibles, j'ai choisi de considérer les bibliothèques Boost supplémentaires si elles sont soit directement fournies, soit triviales à mettre en œuvre.
libuv Boost
Event Loop: yes Asio
Threadpool: yes Asio + Threads
Threading:
Threads: yes Threads
Synchronization: yes Threads
File System Operations:
Synchronous: yes FileSystem
Asynchronous: yes Asio + Filesystem
Timers: yes Asio
Scatter/Gather I/O\[1\]: no Asio
Networking:
ICMP: no Asio
DNS Resolution: async-only Asio
SSL: no Asio
TCP: async-only Asio
UDP: async-only Asio
Signal:
Handling: yes Asio
Sending: yes no
IPC:
UNIX Domain Sockets: yes Asio
Windows Named Pipe: yes Asio
Process Management:
Detaching: yes Process
I/O Pipe: yes Process
Spawning: yes Process
System Queries:
CPU: yes no
Network Interface: yes no
Serial Ports: no yes
TTY: yes no
Shared Library Loading: yes Extension\[2\]
1. <a href="https://en.wikipedia.org/wiki/Vectored_I/O" rel="noreferrer">E/S de diffusion/récolte </a>.
2. <a href="https://web.archive.org/web/20150527052526im_/http://boost-extension.redshoelace.com:80/docs/boost/extension/index.html" rel="noreferrer">Boost.Extension </a>n'a jamais été soumis pour examen à Boost. Comme indiqué <a href="https://web.archive.org/web/20170318102850im_/http://blog.redshoelace.com/2010/01/explanation.html" rel="noreferrer">aquí </a>l'auteur considère qu'il est complet.
Bien que la libuv et Boost.Asio fournissent toutes deux des boucles d'événements, il existe quelques différences subtiles entre les deux :
uv_default_loop()
), plutôt que de créer une nouvelle boucle ( uv_loop_new()
), car un autre composant peut exécuter la boucle par défaut.io_service
sont leurs propres boucles qui permettent l'exécution de plusieurs threads. Pour cela, Boost.Asio effectue verrouillage interne au prix d'une certaine performance . Révision de Boost.Asio histoire indique qu'il y a eu plusieurs améliorations des performances pour minimiser le verrouillage.uv_queue_work
. La taille du pool de threads est configurable via la variable d'environnement UV_THREADPOOL_SIZE
. Le travail sera exécuté en dehors de la boucle d'événement et dans le pool de threads. Une fois le travail terminé, le gestionnaire d'achèvement sera mis en file d'attente pour être exécuté dans la boucle d'événements.io_service
peuvent facilement fonctionner comme une seule entité grâce à io_service
permettant à plusieurs threads d'invoquer run
. Cela confie la responsabilité de la gestion et du comportement des fils à l'utilisateur, comme on peut le voir dans l'exemple suivant este exemple.EAGAIN
o EWOULDBLOCK
.kill
et le traitement des signaux avec son uv_signal_t
et uv_signal_*
opérations.kill
mais son signal_set
assure la gestion des signaux.uv_pipe_t
type.local::stream_protocol::socket
o local::datagram_protocol::socket
y windows::stream_handle
.Bien que les API soient différentes en fonction du seul langage, voici quelques différences essentielles :
Dans Boost.Asio, il existe une correspondance biunivoque entre une opération et un gestionnaire. Par exemple, chaque async_write
invoquera l'opération WriteHandler une fois. Ceci est vrai pour la plupart des opérations et des gestionnaires de libuv. Cependant, la fonction uv_async_send
prend en charge un mappage de plusieurs à un. Multiple uv_async_send
Les appels peuvent entraîner le uv_async_cb être appelé une fois.
Lorsqu'il s'agit de tâches, comme la lecture d'un flux/UDP, la gestion de signaux ou l'attente de temporisations, les chaînes d'appel asynchrones de Boost.Asio sont un peu plus explicites. Avec libuv, un watcher est créé pour désigner les intérêts dans un événement particulier. Une boucle est alors lancée pour le watcher, où un callback est fourni. A la réception de l'événement d'intérêts, la callback sera invoquée. D'autre part, Boost.Asio exige qu'une opération soit émise chaque fois que l'application est intéressée par le traitement de l'événement.
Pour illustrer cette différence, voici une boucle de lecture asynchrone avec Boost.Asio, où le async_receive
L'appel sera émis plusieurs fois :
void start()
{
socket.async_receive( buffer, handle_read ); ----.
} |
.----------------------------------------------'
| .---------------------------------------.
V V |
void handle_read( ... ) |
{ |
std::cout << "got data" << std::endl; |
socket.async_receive( buffer, handle_read ); --'
}
Et voici le même exemple avec libuv, où handle_read
est invoqué à chaque fois que le watcher observe que la socket a des données :
uv_read_start( socket, alloc_buffer, handle_read ); --.
|
.-------------------------------------------------'
|
V
void handle_read( ... )
{
fprintf( stdout, "got data\n" );
}
En raison des chaînes d'appel asynchrones de Boost.Asio et des observateurs de libuv, l'allocation de la mémoire se produit souvent à des moments différents. Avec les watchers, libuv reporte l'allocation jusqu'à ce qu'elle reçoive un événement qui nécessite de la mémoire à gérer. L'allocation se fait par le biais d'une callback utilisateur, invoquée en interne à libuv, et reporte la responsabilité de la désallocation sur l'application. D'un autre côté, de nombreuses opérations de Boost.Asio requièrent que la mémoire soit allouée avant d'émettre l'opération asynchrone, comme dans le cas de la fonction buffer
pour async_read
. Boost.Asio fournit null_buffers
qui peut être utilisé pour écouter un événement, permettant aux applications de différer l'allocation de mémoire jusqu'à ce que la mémoire soit nécessaire, bien que cela soit déprécié.
Cette différence d'allocation de mémoire se présente également dans le cadre de la bind->listen->accept
boucle. Avec libuv, uv_listen
crée une boucle d'événements qui invoquera le rappel de l'utilisateur lorsqu'une connexion est prête à être acceptée. Cela permet à l'application de différer l'allocation du client jusqu'à ce qu'une connexion soit tentée. D'un autre côté, la méthode de Boost.Asio listen
ne change que l'état de la acceptor
. Le site async_accept
écoute l'événement de connexion, et exige que le pair soit alloué avant d'être invoqué.
Malheureusement, je ne dispose pas de chiffres de référence concrets pour comparer libuv et Boost.Asio. Cependant, j'ai observé des performances similaires en utilisant les bibliothèques dans des applications en temps réel et en temps quasi réel. Si vous souhaitez obtenir des chiffres concrets, l'indice de performance de libuv test d'évaluation peut servir de point de départ.
De plus, alors que le profilage devrait être effectué pour identifier les goulots d'étranglement réels, soyez attentif aux allocations de mémoire. Pour libuv, la stratégie d'allocation de mémoire est principalement limitée au callback de l'allocateur. D'autre part, l'API de Boost.Asio ne permet pas de callback d'allocateur, et pousse plutôt la stratégie d'allocation à l'application. Cependant, les handlers/callbacks de Boost.Asio peuvent être copiés, alloués et désalloués. Boost.Asio permet aux applications de fournir allocation de mémoire personnalisée afin de mettre en œuvre une stratégie d'allocation de mémoire pour les gestionnaires.
Le développement d'Asio remonte à au moins OCT-2004, et il a été accepté dans Boost 1.35 le 22-MAR-2006 après avoir subi une évaluation par les pairs de 20 jours. Il a également servi d'implémentation de référence et d'API pour les projets suivants Proposition de bibliothèque en réseau pour TR2 . Boost.Asio a une bonne dose de documentation bien que son utilité varie d'un utilisateur à l'autre.
L'API a également une sensation assez cohérente. De plus, les opérations asynchrones sont explicites dans le nom de l'opération. Par exemple, accept
est un blocage synchrone et async_accept
est asynchrone. L'API fournit des fonctions gratuites pour les tâches d'E/S courantes, par exemple, la lecture d'un flux jusqu'à ce qu'un message d'erreur soit envoyé. \r\n
est lu. Une attention particulière a également été accordée à la dissimulation de certains détails spécifiques au réseau, tels que le nom de l'utilisateur et le numéro de téléphone. ip::address_v4::any()
représentant l'adresse "toutes les interfaces" de 0.0.0.0
.
Enfin, Boost 1.47+ fournit suivi des manipulateurs qui peut s'avérer utile lors du débogage, ainsi que la prise en charge de C++11.
Sur la base de leurs graphiques github, le développement de Node.js remonte à au moins FEB-2009 et le développement de la Libuv remonte à MAR-2011 . Le site uvbook est un endroit idéal pour une introduction à la libuv. La documentation de l'API est aquí .
Dans l'ensemble, l'API est assez cohérente et facile à utiliser. Une anomalie qui peut être une source de confusion est la suivante uv_tcp_listen
crée une boucle d'observation. Ceci est différent des autres observateurs qui ont généralement une uv_*_start
y uv_*_stop
paire de fonctions pour contrôler la vie de la boucle watcher. De plus, certaines des uv_fs_*
Les opérations ont une quantité décente d'arguments (jusqu'à 7). Le comportement synchrone et asynchrone étant déterminé par la présence d'un callback (le dernier argument), la visibilité du comportement synchrone peut être diminuée.
Enfin, un coup d'œil rapide sur la libuv historique des commandes montre que les développeurs sont très actifs.
Ok. J'ai une certaine expérience dans l'utilisation des deux bibliothèques et je peux clarifier certaines choses.
Tout d'abord, d'un point de vue conceptuel, ces bibliothèques sont de conception très différente. Elles ont des architectures différentes, car elles sont de taille différente. Boost.Asio est une grande bibliothèque réseau destinée à être utilisée avec les protocoles TCP/UDP/ICMP, POSIX, SSL, etc. Libuv n'est qu'une couche d'abstraction multiplateforme pour les protocoles TCP/UDP/ICMP. IOCP pour Node.js, de manière prédominante. Ainsi, libuv est fonctionnellement un sous-ensemble de Boost.Asio (caractéristiques communes uniquement TCP/UDP Sockets threads, timers). Dans ces conditions, nous pouvons comparer ces bibliothèques en utilisant seulement quelques critères :
Performances d'IOCP - Je ne vois pas de grandes différences, car ces deux bibliothèques font abstraction de l'API du système d'exploitation sous-jacent. Mais elles le font d'une manière différente : Asio utilise fortement les fonctionnalités C++ comme les templates et parfois TMP. Libuv est une bibliothèque C native. Néanmoins, la réalisation d'IOCP par Asio est très efficace. Les sockets UDP dans Asio ne sont pas assez bons, il est préférable d'utiliser libuv pour eux.
Intégration avec les nouvelles fonctionnalités du C++ : Asio est meilleur (Asio 1.51 utilise largement le modèle asynchrone C++11, la sémantique des déplacements, les templates variadiques). En ce qui concerne la maturité, Asio est un projet plus stable et plus mature avec une bonne documentation (si on la compare à la description des en-têtes de libuv), beaucoup d'informations sur Internet (discussions vidéo, blogs) : http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=1 ,etc.) et même des livres (pas pour les professionnels mais néanmoins : http://en.highscore.de/cpp/boost/index.html ). Libuv n'a qu'un seul livre en ligne (mais également bon) http://nikhilm.github.com/uvbook/index.html et plusieurs conférences vidéo, il sera donc difficile de connaître tous les secrets (cette bibliothèque en a beaucoup). Pour une discussion plus spécifique sur les fonctions, voir mes commentaires ci-dessous.
Pour conclure, je dirais que tout dépend de vos objectifs, de votre projet et de ce que vous comptez faire concrètement.
Ce qui compte, c'est votre compétence technique et votre expérience. Salutations cordiales d'un Cubain.
Je suis d'accord avec tous vos points sauf la documentation d'Asio. La documentation officielle ne rend pas justice à cette merveilleuse bibliothèque. Il y a un tas d'autres documents et une conférence de l'auteur que j'ai trouvée très utile. Et je ne suis pas tombé sur un livre pour Asio. Pouvez-vous le lier dans votre réponse ? Ce serait très utile.
Pour ce qui est des livres, j'ai édité ma réponse mais je pense que vous l'avez déjà vue (malheureusement, il n'y a pas de livre entièrement consacré à Boost - seulement des informations éparses).
L'une des grandes différences est que l'auteur d'Asio (Christopher Kohlhoff) prépare sa bibliothèque pour qu'elle soit incluse dans la bibliothèque standard C++. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2175.pdf y http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4370.html
Ajout du statut de portabilité : Au moment de poster cette réponse et selon mes propres essais :
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
24 votes
Posons cette question et obtenons de bonnes réponses !
0 votes
\o / J'espère que nous aurons des réponses perspicaces !