Réponses:
Boost.Asio est une bibliothèque C ++ qui a commencé par se concentrer sur la mise en réseau, mais ses capacités d'E / S asynchrones ont été étendues à d'autres ressources. De plus, Boost.Asio faisant partie des bibliothèques Boost, sa portée est légèrement réduite pour éviter la duplication avec d'autres bibliothèques Boost. Par exemple, Boost.Asio ne fournira pas d'abstraction de thread, comme Boost.Thread en fournit déjà une.
D'autre part, libuv est une bibliothèque C conçue pour être la couche de plate - forme pour Node.js . Il fournit une abstraction pour IOCP sous Windows, kqueue sous macOS et epoll sous Linux. En outre, il semble que sa portée ait légèrement augmenté pour inclure les abstractions et les fonctionnalités, telles que les threads, les pools de threads et la communication entre les threads.
Au fond, chaque bibliothèque fournit une boucle d'événement et des capacités d'E / S asynchrones. Ils se chevauchent pour certaines des fonctionnalités de base, telles que les minuteries, les sockets et les opérations asynchrones. libuv a une portée plus large et fournit des fonctionnalités supplémentaires, telles que les abstractions de thread et de synchronisation, les opérations de système de fichiers synchrones et asynchrones, la gestion des processus, etc. des capacités telles que ICMP, SSL, des opérations de blocage et de non-blocage synchrones et des opérations de niveau supérieur 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 certaines des principales fonctionnalités. Étant donné que les développeurs utilisant Boost.Asio ont souvent d'autres bibliothèques Boost disponibles, j'ai choisi d'envisager des bibliothèques Boost supplémentaires si elles sont directement fournies ou triviales à implémenter.
libuv Boost Boucle d'événement: oui Asio Threadpool: oui Asio + Threads Filetage: Fils: oui Fils Synchronisation: oui Threads Opérations du système de fichiers: Synchrone: oui FileSystem Asynchrone: oui Asio + Filesystem Minuteurs: oui Asio E / S Scatter / Gather [1] : pas d'Asio La mise en réseau: ICMP: pas d'Asio Résolution DNS: Asio uniquement asynchrone SSL: pas d'Asio TCP: Asio uniquement asynchrone UDP: Asio uniquement asynchrone Signal: Manipulation: oui Asio Envoi: oui non IPC: Sockets de domaine UNIX: oui Asio Canal nommé Windows: oui Asio La gestion des processus: Détachement: oui Processus Tuyau d'E / S: oui Processus Apparition: oui Processus Requêtes système: CPU: oui non Interface réseau: oui non Ports série: non oui ATS: oui non Chargement de la bibliothèque partagée: oui Extension [2]
2. Boost.Extension n'a jamais été soumis pour examen à Boost. Comme indiqué ici , l'auteur considère qu'il est complet.
Bien que libuv et Boost.Asio fournissent 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 à plusieurs threads de s'exécuter. Pour prendre en charge ce Boost.Asio effectue un verrouillage interne au prix de certaines performances . Révision de Boost.Asio l'histoire indique qu'il ya eu plusieurs améliorations de 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énements et dans le pool de threads. Une fois le travail terminé, le gestionnaire d'achèvement sera mis en file d'attente pour s'exécuter dans la boucle d'événements.io_service
peut facilement fonctionner comme un en raison de l' io_service
autorisation de plusieurs threads à invoquer run
. Cela place la responsabilité de la gestion et du comportement des threads pour l'utilisateur, comme on peut le voir dans cet exemple.EAGAIN
ou EWOULDBLOCK
.kill
et une gestion du signal avec son uv_signal_t
type et ses uv_signal_*
opérations.kill
, mais signal_set
fournit une gestion du signal.uv_pipe_t
type.local::stream_protocol::socket
ou local::datagram_protocol::socket
, et windows::stream_handle
.Bien que les API soient différentes en fonction du seul langage, voici quelques différences clés:
Dans Boost.Asio, il existe un mappage un à un entre une opération et un gestionnaire. Par exemple, chaque async_write
opération invoquera le WriteHandler une fois. Cela est vrai pour de nombreuses opérations et gestionnaires libuv. Cependant, libuv's uv_async_send
prend en charge un mappage plusieurs-à-un. Plusieurs uv_async_send
appels peuvent entraîner l' appel de uv_async_cb une fois.
Lorsque vous traitez une tâche, comme la lecture d'un flux / UDP, la gestion des signaux ou l'attente de temporisateurs, les chaînes d'appels asynchrones de Boost.Asio sont un peu plus explicites. Avec libuv, un observateur est créé pour désigner les intérêts d'un événement particulier. Une boucle est alors démarrée pour l'observateur, où un rappel est fourni. Dès réception de l'événement d'intérêt, le rappel sera invoqué. En revanche, Boost.Asio requiert qu'une opération soit émise chaque fois que l'application souhaite gérer l'événement.
Pour illustrer cette différence, voici une boucle de lecture asynchrone avec Boost.Asio, où l' async_receive
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 l'observateur observe que le socket contient 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'appels asynchrones dans Boost.Asio et des observateurs dans libuv, l'allocation de mémoire se produit souvent à des moments différents. Avec les observateurs, libuv diffère l'allocation jusqu'à ce qu'il reçoive un événement qui nécessite de la mémoire pour être géré. L'allocation se fait via un rappel utilisateur, invoqué en interne dans libuv, et reporte la responsabilité de désallocation de l'application. D'un autre côté, de nombreuses opérations Boost.Asio nécessitent que la mémoire soit allouée avant d'émettre l'opération asynchrone, comme dans le cas du buffer
for 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 obsolète.
Cette différence d'allocation de mémoire se présente également dans 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. En revanche, Boost.Asio listen
ne change que l'état du acceptor
. L' async_accept
écoute de l'événement de connexion et requiert que l'homologue soit alloué avant d'être appelé.
Malheureusement, je n'ai 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 des chiffres précis sont souhaités, le test de référence de libuv peut servir de point de départ.
De plus, alors que le profilage doit être effectué pour identifier les goulots d'étranglement réels, soyez conscient des allocations de mémoire. Pour libuv, la stratégie d'allocation de mémoire est principalement limitée au rappel d'allocateur. D'un autre côté, l'API de Boost.Asio ne permet pas de rappel d'allocateur et pousse plutôt la stratégie d'allocation à l'application. Cependant, les gestionnaires / rappels dans Boost.Asio peuvent être copiés, alloués et désalloués. Boost.Asio permet aux applications de fournir des fonctions d' allocation de mémoire personnalisées 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 un examen par les pairs de 20 jours. Il a également servi d'implémentation de référence et d'API pour la proposition de bibliothèque de mise en réseau pour TR2 . Boost.Asio a une bonne quantité de documentation , bien que son utilité varie d'un utilisateur à l'autre.
L'API a également une sensation assez cohérente. En outre, 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'à la lecture d'un \r\n
. Une attention a également été accordée à masquer certains détails spécifiques au réseau, tels que la ip::address_v4::any()
représentation de l'adresse "toutes les interfaces" de 0.0.0.0
.
Enfin, Boost 1.47+ fournit un suivi des gestionnaires , 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 libuv à MAR-2011 . L' uvbook est un excellent endroit pour une introduction libuv. La documentation de l'API est ici .
Dans l'ensemble, l'API est assez cohérente et facile à utiliser. Une anomalie qui peut être une source de confusion est la uv_tcp_listen
création d'une boucle d'observation. Ceci est différent des autres observateurs qui ont généralement une uv_*_start
et une uv_*_stop
paire de fonctions pour contrôler la durée de vie de la boucle de surveillance. De plus, certaines uv_fs_*
opérations ont une quantité décente d'arguments (jusqu'à 7). Le comportement synchrone et asynchrone étant déterminé sur la présence d'un rappel (le dernier argument), la visibilité du comportement synchrone peut être diminuée.
Enfin, un rapide coup d'œil à l'historique des validations de libuv montre que les développeurs sont très actifs.
uv_async_send
appels et les gérer tous avec un seul rappel. Il est documenté ici . Merci aussi à tous.
D'accord. J'ai une certaine expérience dans l'utilisation des deux bibliothèques et je peux clarifier certaines choses.
D'abord, d'un point de vue conceptuel, ces bibliothèques sont très différentes dans leur conception. Ils ont des architectures différentes, car ils sont d'échelle différente. Boost.Asio est une grande bibliothèque de mise en réseau destinée à être utilisée avec les protocoles TCP / UDP / ICMP, POSIX, SSL, etc. Libuv est juste une couche pour l'abstraction multiplateforme d' IOCP pour Node.js, principalement. Libuv est donc fonctionnellement un sous-ensemble de Boost.Asio (fonctionnalités communes uniquement aux threads Sockets TCP / UDP, minuteries). Cela étant, nous pouvons comparer ces bibliothèques en utilisant seulement quelques critères:
Intégration avec de nouvelles fonctionnalités C ++: Asio est meilleur (Asio 1.51 utilise largement le modèle asynchrone C ++ 11, déplace la sémantique, les modèles variadiques) .En ce qui concerne la maturité, Asio est un projet plus stable et mature avec une bonne documentation (si on le compare à libuv description des en-têtes), beaucoup d'informations sur Internet (conférences 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 aussi bien) http://nikhilm.github.com/uvbook/index.htmlet plusieurs discussions vidéo, il sera donc difficile de connaître tous les secrets (cette bibliothèque en a beaucoup). Pour une discussion plus spécifique des fonctions, voir mes commentaires ci-dessous.
En conclusion, je dois dire que tout dépend de vos objectifs, de votre projet et de ce que vous comptez concrètement faire.
Une énorme différence est que l'auteur d'Asio (Christopher Kohlhoff) prépare sa bibliothèque pour l'inclure dans la bibliothèque standard C ++, voir http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2175 .pdf et http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4370.html
Ajout du statut de portabilité: Au moment de publier cette réponse et selon mes propres tentatives: