¿Cómo se compara libuv con Boost / ASIO?


Me interesarían aspectos como:

  • alcance / características
  • rendimiento
  • vencimiento
Author: Sam Miller, 2012-07-11

3 answers

Ámbito de aplicación

Boost.Asio es una biblioteca de C++ que comenzó con un enfoque en redes, pero sus capacidades de E/S asincrónicas se han extendido a otros recursos. Además, con Boost.Asio es 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 hilo, como Boost.Thread ya proporciona uno.

Por otro lado, libuv es una biblioteca C diseñada para ser la capa de plataforma para el nodo .js . Proporciona una abstracción a IOCP para Windows y libev en sistemas Unix. Aunque hay esfuerzos para eliminar libev como se indica en este problema. Además, parece que su alcance ha aumentado ligeramente para incluir abstracciones y funcionalidad, como hilos, threadpools y comunicación entre hilos.

En su núcleo, cada biblioteca proporciona un bucle de eventos y capacidades de E/S asincrónicas. Tienen superposición para algunas de las características básicas, como temporizadores, sockets y operaciones asíncronas. libuv tiene un alcance más amplio y proporciona funcionalidad adicional, como abstracciones de subprocesos y sincronización, operaciones de sistemas de archivos síncronos y asíncronos, gestión de procesos, etc. En contraste, Boost.Las superficies de enfoque de red originales de Asio, ya que proporciona un conjunto más rico de capacidades relacionadas con la red, como ICMP, SSL, bloqueo síncrono y operaciones sin bloqueo y operaciones de nivel superior para tareas comunes, incluida la lectura de una transmisión hasta que se reciba una nueva línea.


Lista de características

Aquí está la breve comparación lado a lado sobre algunas de las características principales. Desde desarrolladores usando Boost.Asio a menudo tiene otras bibliotecas Boost disponibles, he optado por considerar bibliotecas Boost adicionales si se proporcionan directamente o son triviales de implementar.

                         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. Dispersar / Reunir E / S .

2. Aumentar.La extensión nunca fue enviada para su revisión a Boost. Como se señala aquí, el autor lo considera completo.

Bucle de eventos

Mientras tanto libuv y Boost.Asio proporcionar bucles de eventos, hay algunas diferencias sutiles entre los dos:

  • Si bien libuv admite varios bucles de eventos, no admite la ejecución del mismo bucle desde varios subprocesos. Por esta razón, hay que tener cuidado cuando usando el bucle predeterminado (uv_default_loop()), en lugar de crear un nuevo bucle (uv_loop_new()), ya que otro componente puede estar ejecutando el bucle predeterminado.
  • Aumentar.Asio no tiene la noción de un bucle predeterminado; todos io_service son sus propios bucles que permiten ejecutar múltiples subprocesos. Para apoyar este Impulso.Asio realizabloqueo interno a costa de algunosrendimiento . Impulsar.La revisión de Asio historia indica que ha habido varias mejoras de rendimiento para minimizar el bloqueo.

Threadpool

  • libuv proporciona un threadpool a través de uv_queue_work. El tamaño de threadpool es un detalle de implementación y no parece configurable a través de la API. El trabajo se ejecutará fuera del bucle de eventos y dentro del threadpool. Una vez que se complete el trabajo, el controlador de finalización se pondrá en cola para ejecutarse dentro del bucle de eventos.
  • Mientras Boost.Asio no proporciona un threadpool, el io_service puede funcionar fácilmente como uno como resultado de io_service permitiendo que múltiples hilos invoquen run. Esto coloca la responsabilidad de la gestión de subprocesos y el comportamiento al usuario, como se puede ver en este ejemplo.

Enhebrado y sincronización

  • libuv proporciona una abstracción a los subprocesos y tipos de sincronización.
  • Aumentar.Thread proporciona un hilo y tipos de sincronización. Muchos de estos tipos siguen de cerca el estándar C++11, pero también proporcionan algunas extensiones. Como resultado de Boost.Asio permite que múltiples hilos ejecuten un solo bucle de eventos, proporciona strands como un medio para crear una invocación secuencial de controladores de eventos sin usar mecanismos de bloqueo explícitos.

Operaciones del Sistema de Archivos

  • libuv proporciona una abstracción a muchas operaciones del sistema de archivos. Hay una función por operación, y cada operación puede ser de bloqueo síncrono o asíncrono. Si se proporciona una devolución de llamada, entonces la operación será ejecutado de forma asíncrona dentro de un threadpool interno. Si no se proporciona una devolución de llamada, entonces la llamada será un bloqueo síncrono.
  • Aumentar.Filesystem proporciona llamadas de bloqueo síncronas para muchas operaciones del sistema de archivos. Estos se pueden combinar con Boost.Asio y un threadpool para crear operaciones asíncronas del sistema de archivos.

Redes

  • libuv soporta operaciones asíncronas en sockets UDP y TCP, así como resolución DNS. Aplicación los desarrolladores deben tener en cuenta que los descriptores de archivo subyacentes están configurados en no bloqueo. Por lo tanto, las operaciones síncronas nativas deben verificar los valores devueltos y errno para EAGAIN o EWOULDBLOCK.
  • Aumentar.Asio es un poco más rico en su soporte de redes. Además, muchas de las características que ofrece la red de libuv, Boost.Asio soporta sockets SSL e ICMP. Además, Boost.Asio proporciona operaciones de bloqueo síncrono y sin bloqueo síncrono, además de su operaciones asíncronas. Hay numerosas funciones independientes que proporcionan operaciones comunes de nivel superior, como leer una cantidad determinada de bytes, o hasta que se lea un carácter delimitador especificado.

Señal

  • libuv proporciona una abstracción kill y manejo de señales con su tipo uv_signal_t y operaciones uv_signal_*. En este momento, solo el bucle de eventos predeterminado admite señales.
  • Aumentar.Asio no proporciona una abstracción a kill, pero su signal_set_service proporciona manejo de señales.

IPC


Diferencias de API

Si bien las API son diferentes solo en función del idioma, aquí hay algunas claves diferencias:

Operación y Asociación del Manejador

Dentro de Boost.Asio, hay un mapeo uno a uno entre una operación y un manejador. Por ejemplo, cada async_write la operación invocará el WriteHandler una vez. Esto es cierto para muchas de las operaciones y manejadores de libuv. Sin embargo, el uv_async_send de libuv soporta una asignación de muchos a uno. Múltiples llamadas uv_async_send pueden resultar en que el uv_async_cb sea llamado una vez.

Call Chains vs. Watcher Bucles

Cuando se trata de tareas, como leer desde un flujo/UDP, manejar señales o esperar temporizadores, aumente.Las cadenas de llamadas asíncronas de 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 se interesados en manejar el evento.

Para ayudar a ilustrar esta diferencia, aquí hay un bucle 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" );
}

Asignación de memoria

Como resultado de las cadenas de llamadas asíncronas en Boost.Asio y los observadores en libuv, la asignación de memoria a menudo ocurre en tiempos diferentes. Con watchers, libuv aplaza 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 de usuario, invocada internamente a libuv, y aplaza la responsabilidad de desasignación de la aplicación. Por otro lado, muchos de los Boost.Las operaciones Asio requieren que se asigne la memoria antes de emitir la operación asíncrona, como el caso de buffer para async_read. Impulsar.Asio proporciona null_buffers, que se puede utilizar para escuchar un evento, lo que permite a las aplicaciones aplazar la asignación de memoria hasta que se necesite memoria.

Esta diferencia de asignación de memoria también se presenta dentro del bucle bind->listen->accept. 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 aplace la asignación del cliente hasta que se intente una conexión. Por otro lado, Boost.Asio's listen solo cambia el estado de la acceptor. Las async_accept escucha el evento de conexión y requiere que el par sea asignado antes de ser invocado.


Rendimiento

Desafortunadamente, no tengo ningún número de referencia concreto para comparar libuv y Boost.Asio. Sin embargo, he observado un rendimiento similar utilizando 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 punto.

Además, mientras que el perfilado debe hacerse para identificar los 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, Boost.La API de Asio no permite una devolución de llamada del asignador, y en su lugar envía la estrategia de asignación a la aplicación. Sin embargo, los handlers/callbacks en Boost.Asio puede ser copiado, asignado y desasignado. Impulsar.Asio permite que las aplicaciones proporcionen custom memory allocation funciona para implementar una estrategia de asignación de memoria para los controladores.


Vencimiento

Aumentar.Asio

El desarrollo de Asio se remonta al menos a OCTUBRE de 2004, y fue aceptado en Boost 1.35 el 22 de marzo de 2006 después de someterse a una revisión por pares de 20 días. También sirvió como la implementación de referencia y API para Propuesta de Biblioteca de redes para TR2. Impulsar.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 asíncronas 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 comunes de E / S, por ejemplo, leer desde un flujo hasta que se lee un \r\n. También se ha prestado atención a ocultar algunos detalles específicos de la red, como el ip::address_v4::any() que representa el " todas las interfaces" dirección de 0.0.0.0.

Finalmente, Boost 1.47+ proporciona seguimiento del controlador, que puede resultar útil al depurar, así como soporte para C++11.

Libuv

Basado en sus gráficos de github, Node.el desarrollo de js se remonta al menos a FEB-2009, y el desarrollo de libuv se remonta a MAR-2011. El uvbook es un gran lugar para una introducción a libuv. La API está documentada en forma de un encabezado detallado, pero podría todavía utilizar contribuciones en algunas áreas.

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 bucle de vigilante. Esto es diferente a otros observadores que generalmente tienen un par de funciones uv_*_start y uv_*_stop para controlar la vida del bucle watcher. Además, algunas de las operaciones uv_fs_* tienen una cantidad decente de argumentos (hasta 7). Con el comportamiento síncrono y asíncrono se determina en la presencia de un callback (el último argumento), la visibilidad del comportamiento síncrono puede ser disminuida.

Finalmente, un rápido vistazo al historial de confirmaciones de libuv muestra que los desarrolladores están muy activos.

 432
Author: Tanner Sansbury,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-06 07:41:23

Ok. 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. Impulsar.Asio es una gran biblioteca de redes 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 Nodo.js, predominantemente. Así que libuv es funcionalmente un subconjunto de Impulsar.Asio (características comunes solo TCP/UDP Sockets threads, temporizadores). Siendo ese el caso, podemos comparar estas bibliotecas usando solo unos pocos criterios:

  1. Integración con Node.js-Libuv es considerablemente mejor porque está dirigido a esto (podemos integrarlo completamente y usarlo en todos los aspectos, por ejemplo, en la nube, por ejemplo, windows azure). Pero Asio también implementa casi la misma funcionalidad que en Node.js event queue driven environment.
  2. Rendimiento del IOCP-No pude ver muy bien diferencias, porque ambas bibliotecas abstraen la API del sistema operativo subyacente. Pero lo hacen de una manera diferente: Asio usa en gran medida características de C++ como plantillas y, a veces, TMP. Libuv es una biblioteca-C nativa. Pero sin embargo la realización Asio del IOCP es muy eficiente. Los sockets UDP en Asio no son lo suficientemente buenos, es mejor usar libuv para ellos.

    Integración con nuevas características de C++: Asio es mejor (Asio 1.51 utiliza ampliamente el modelo asíncrono C++11, semántica de movimiento, plantillas variádicas). madurez, Asio es un proyecto más estable y maduro con buena documentación (si se compara con la descripción de los encabezados de libuv), mucha información a través de Internet (charlas de video, 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, pero sin embargo: http://en.highscore.de/cpp/boost/index.html ). Libuv tiene solo un libro en línea (pero también es bueno) http://nikhilm.github.com/uvbook/index.html y varias charlas en video, 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 ver mis comentarios a continuación.

Como conclusión, debo decir que todo depende de sus propósitos, su proyecto y lo que concretamente pretende hacer.

 45
Author: Oleksandr Karaberov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-02 20:51:32

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++, ver 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

 14
Author: Vinnie Falco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-25 14:36:57