Respuestas:
Boost.Asio es una biblioteca de C ++ que comenzó con un enfoque en las redes, pero sus capacidades de E / S asíncronas se han extendido a otros recursos. Además, con Boost.Asio como parte de las bibliotecas de Boost, su alcance se reduce ligeramente para evitar la duplicación con otras bibliotecas de Boost. Por ejemplo, Boost.Asio no proporcionará una abstracción de subproceso, ya que Boost.Thread ya proporciona uno.
Por otro lado, libuv es una biblioteca de C diseñado para ser la capa de plataforma para Node.js . Proporciona una abstracción para IOCP en Windows, kqueue en macOS y epoll en Linux. Además, parece que su alcance ha aumentado ligeramente para incluir abstracciones y funcionalidades, como hilos, agrupaciones de hilos y comunicación entre hilos.
En esencia, cada biblioteca proporciona un bucle de eventos y capacidades de E / S asíncronas. Se superponen para algunas de las características básicas, como temporizadores, sockets y operaciones asincrónicas. libuv tiene un alcance más amplio y proporciona funcionalidad adicional, como abstracciones de hilos y sincronización, operaciones de sistemas de archivos síncronos y asíncronos, gestión de procesos, etc. capacidades, como ICMP, SSL, operaciones de bloqueo sincrónico y sin bloqueo, y operaciones de nivel superior para tareas comunes, incluida la lectura de una secuencia hasta que se recibe una nueva línea.
Aquí está la breve comparación lado a lado de algunas de las principales características. Dado que los desarrolladores que usan Boost.Asio a menudo tienen otras bibliotecas de Boost disponibles, he optado por considerar bibliotecas de Boost adicionales si se proporcionan directamente o son triviales de implementar.
libuv Boost Bucle de eventos: sí Asio Threadpool: sí Asio + Threads Roscado: Hilos: sí Hilos Sincronización: sí Hilos Operaciones del sistema de archivos: Sincrónico: sí FileSystem Asíncrono: sí Asio + Sistema de archivos Temporizadores: sí Asio Scatter / Gather I / O [1] : no Asio Redes: ICMP: no Asio Resolución DNS: Asio solo asíncrono SSL: no Asio TCP: Asio solo asíncrono UDP: Asio solo asíncrono Señal: Manejo: sí Asio Envío: si no IPC: Sockets de dominio UNIX: sí Asio Canalización con nombre de Windows: sí Asio Gestión de proceso: Separación: sí Proceso Tubería de E / S: sí Proceso Desove: sí Proceso Consultas del sistema: CPU: sí no Interfaz de red: sí no Puertos seriales: no si TTY: si no Carga de la biblioteca compartida: sí Extensión [2]
1. dispersión / agrupación I / O .
2. Boost.Extension nunca se envió para su revisión a Boost. Como se señaló aquí , el autor lo considera completo.
Si bien tanto libuv como Boost.Asio proporcionan bucles de eventos, existen algunas diferencias sutiles entre los dos:
uv_default_loop()
), en lugar de crear un nuevo bucle ( uv_loop_new()
), ya que otro componente puede estar ejecutando el bucle predeterminado.io_service
son sus propios bucles que permiten ejecutar múltiples subprocesos. Para admitir este Boost.Asio realiza un bloqueo interno a costa de cierto rendimiento . El historial de revisión de Boost.Asio indica que ha habido varias mejoras de rendimiento para minimizar el bloqueo.uv_queue_work
. El tamaño del conjunto de hilos es configurable a través de la variable de entorno UV_THREADPOOL_SIZE
. El trabajo se ejecutará fuera del bucle de eventos y dentro del conjunto de hilos. Una vez que se completa el trabajo, el controlador de finalización se pondrá en cola para ejecutarse dentro del bucle de eventos.io_service
puede funcionar fácilmente como uno solo porque io_service
permite invocar varios subprocesos run
. Esto pone la responsabilidad de la gestión de hilos y el comportamiento del usuario, como se puede ver en este ejemplo.EAGAIN
o EWOULDBLOCK
.kill
y manejo de señal con su uv_signal_t
tipo y uv_signal_*
operaciones.kill
, pero signal_set
proporciona manejo de señal.uv_pipe_t
tipo.local::stream_protocol::socket
o local::datagram_protocol::socket
, y windows::stream_handle
.Si bien las API son diferentes según el idioma solo, aquí hay algunas diferencias clave:
Dentro de Boost.Asio, hay un mapeo uno a uno entre una operación y un controlador. Por ejemplo, cada async_write
operación invocará al WriteHandler una vez. Esto es cierto para muchas de las operaciones y controladores de libuv. Sin embargo, libuv's uv_async_send
admite un mapeo de muchos a uno. Varias uv_async_send
llamadas pueden provocar que se llame a uv_async_cb una vez.
Cuando se trata de tareas, como leer desde un flujo / UDP, manejar señales o esperar temporizadores, las cadenas de llamadas asíncronas de Boost.Asio son un poco más explícitas. Con libuv, se crea un observador para designar intereses en un evento en particular. Luego se inicia un bucle para el observador, donde se proporciona una devolución de llamada. Al recibir el evento de intereses, se invocará la devolución de llamada. Por otro lado, Boost.Asio requiere que se emita una operación cada vez que la aplicación esté interesada en manejar el evento.
Para ayudar a ilustrar esta diferencia, aquí hay un ciclo de lectura asíncrono con Boost.Asio, donde la async_receive
llamada se emitirá varias veces:
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 ); --'
}
Y aquí está el mismo ejemplo con libuv, donde handle_read
se invoca cada vez que el observador observa que el socket tiene datos:
uv_read_start( socket, alloc_buffer, handle_read ); --.
|
.-------------------------------------------------'
|
V
void handle_read( ... )
{
fprintf( stdout, "got data\n" );
}
Como resultado de las cadenas de llamadas asincrónicas en Boost.Asio y los observadores en libuv, la asignación de memoria a menudo ocurre en diferentes momentos. Con los observadores, libuv difiere la asignación hasta después de recibir un evento que requiere memoria para manejar. La asignación se realiza a través de una devolución de llamada del usuario, invocada internamente a libuv, y difiere la responsabilidad de desasignación de la aplicación. Por otro lado, muchas de las operaciones Boost.Asio requieren que la memoria se asigne antes de emitir la operación asincrónica, como el caso de buffer
for async_read
. Boost.Asio proporciona null_buffers
, que se puede usar para escuchar un evento, permitiendo que las aplicaciones difieran la asignación de memoria hasta que se necesite memoria, aunque esto está en desuso.
Esta diferencia de asignación de memoria también se presenta dentro del bind->listen->accept
bucle. Con libuv, uv_listen
crea un bucle de eventos que invocará la devolución de llamada del usuario cuando una conexión esté lista para ser aceptada. Esto permite que la aplicación difiera la asignación del cliente hasta que se intente una conexión. Por otro lado, Boost.Asio listen
solo cambia el estado de la acceptor
. Las async_accept
escuchas para el evento de conexión, y requiere que la pareja se asignarán antes de ser invocado.
Desafortunadamente, no tengo ningún número de referencia concreto para comparar libuv y Boost.Asio. Sin embargo, he observado un rendimiento similar al usar las bibliotecas en aplicaciones en tiempo real y casi en tiempo real. Si se desean números duros, la prueba de referencia de libuv puede servir como punto de partida.
Además, aunque se debe realizar un perfil para identificar cuellos de botella reales, tenga en cuenta las asignaciones de memoria. Para libuv, la estrategia de asignación de memoria se limita principalmente a la devolución de llamada del asignador. Por otro lado, la API de Boost.Asio no permite una devolución de llamada del asignador, y en su lugar empuja la estrategia de asignación a la aplicación. Sin embargo, los controladores / devoluciones de llamada en Boost.Asio pueden copiarse, asignarse y desasignarse. Boost.Asio permite que las aplicaciones proporcionen funciones de asignación de memoria personalizadas para implementar una estrategia de asignación de memoria para los manejadores.
El desarrollo de Asio se remonta al menos a OCT-2004, y fue aceptado en Boost 1.35 el 22-MAR-2006 después de someterse a una revisión por pares de 20 días. También sirvió como implementación de referencia y API para la propuesta de biblioteca de red para TR2 . Boost.Asio tiene una buena cantidad de documentación , aunque su utilidad varía de usuario a usuario.
La API también tiene una sensación bastante consistente. Además, las operaciones asincrónicas son explícitas en el nombre de la operación. Por ejemplo, accept
es bloqueo síncrono y async_accept
es asíncrono. La API proporciona funciones gratuitas para tareas de E / S comunes, por ejemplo, leer desde una secuencia hasta que \r\n
se lea una. También se ha prestado atención para ocultar algunos detalles específicos de la red, como la ip::address_v4::any()
representación de la dirección de "todas las interfaces" 0.0.0.0
.
Finalmente, Boost 1.47+ proporciona un seguimiento de controladores , que puede resultar útil al depurar, así como compatibilidad con C ++ 11.
Según sus gráficos de github, el desarrollo de Node.js se remonta al menos a FEB-2009 , y el desarrollo de libuv a MAR-2011 . El uvbook es un gran lugar para una introducción a libuv. La documentación de la API está aquí .
En general, la API es bastante consistente y fácil de usar. Una anomalía que puede ser una fuente de confusión es que uv_tcp_listen
crea un circuito de observación. Esto es diferente de otros observadores de que generalmente tienen una uv_*_start
y uv_*_stop
par de funciones para controlar la vida del bucle observador. Además, algunas de las uv_fs_*
operaciones tienen una cantidad decente de argumentos (hasta 7). Con el comportamiento sincrónico y asincrónico que se determina en presencia de una devolución de llamada (el último argumento), la visibilidad del comportamiento sincrónico puede verse disminuida.
Finalmente, un rápido vistazo al libuv historial de confirmación de muestra que los desarrolladores son muy activos.
uv_async_send
llamadas y manejarlas todas con una sola devolución de llamada. Está documentado aquí . Además, gracias a todos.
Okay. Tengo cierta experiencia en el uso de ambas bibliotecas y puedo aclarar algunas cosas.
Primero, desde un punto de vista conceptual, estas bibliotecas son bastante diferentes en diseño. Tienen arquitecturas diferentes, porque son de diferente escala. Boost.Asio es una gran biblioteca de red destinada a ser utilizada con protocolos TCP / UDP / ICMP, POSIX, SSL, etc. Libuv es solo una capa para la abstracción multiplataforma de IOCP para Node.js, predominantemente. Entonces, libuv es funcionalmente un subconjunto de Boost.Asio (características comunes solo hilos de sockets TCP / UDP, temporizadores). Siendo ese el caso, podemos comparar estas bibliotecas usando solo unos pocos criterios:
Integración con nuevas características de C ++: Asio es mejor (Asio 1.51 usa ampliamente el modelo asíncrono C ++ 11, mueve semántica, plantillas variadas). En cuanto a la madurez, Asio es un proyecto más estable y maduro con buena documentación (si se compara con libuv descripción de encabezados), mucha información a través de Internet (videoconferencias, blogs: http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg = 1 , etc.) e incluso libros (no para profesionales, sin embargo: http://en.highscore.de/cpp/boost/index.html ). Libuv tiene solo un libro en línea (pero también bueno) http://nikhilm.github.com/uvbook/index.htmly varias videoconferencias, por lo que será difícil conocer todos los secretos (esta biblioteca tiene muchos de ellos). Para una discusión más específica de las funciones, vea mis comentarios a continuación.
Como conclusión, debería decir que todo depende de sus propósitos, su proyecto y lo que concretamente tiene la intención de hacer.
Una gran diferencia es que el autor de Asio (Christopher Kohlhoff) está preparando su biblioteca para su inclusión en la Biblioteca estándar de C ++, consulte 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
Agregar el estado de portabilidad: a partir de la publicación de esta respuesta y de acuerdo con mis propios intentos: