Как libuv сравнивается с Boost / ASIO?

меня интересуют такие аспекты, как:

  • объем/характеристики
  • производительность
  • зрелость

3 ответов


область

импульс.Asio - это библиотека C++, которая начиналась с фокусировки на сети, но ее асинхронные возможности ввода-вывода были расширены на другие ресурсы. Дополнительно, с подталкиванием.Asio является частью библиотек Boost, его область немного сужена, чтобы предотвратить дублирование с другими библиотеками Boost. Например, увеличить.Asio не будет предоставлять абстракцию потока, как импульс.Нить уже предоставляет один.

на другая рука,libuv библиотека C предназначена для уровня платформы для узел.js. Он предоставляет абстракцию IOCP для Windows и libev в системах Unix. Хотя есть попытки удалить libev как отметил в этой вопрос. Кроме того, похоже, что его область немного расширилась, чтобы включить абстракции и функциональность, такие как потоки, пулы потоков и Интер-поток связь.

в своей основе каждая библиотека предоставляет цикл событий и асинхронные возможности ввода-вывода. Они имеют перекрытие для некоторых основных функций, таких как таймеры, сокеты и асинхронные операции. libuv имеет более широкую область и предоставляет дополнительные функции, такие как абстракции потоков и синхронизации, синхронные и асинхронные операции файловой системы, управление процессами и т. д. В отличие от наддува.Поверхности фокуса сети Asio первоначально, по мере того как она обеспечивает a более богатый набор сетевых возможностей, таких как ICMP, SSL, синхронные блокирующие и неблокирующие операции и операции более высокого уровня для общих задач, включая чтение из потока до получения новой строки.


Список Функций

вот краткое параллельное сравнение по некоторым основным функциям. Так как разработчики используют Boost.Asio часто имеют другие библиотеки Boost, я решил рассмотреть дополнительные библиотеки Boost, если они есть либо непосредственно предоставлено, либо тривиально реализовано.

                         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. Scatter/Gather I/O.

2. импульс.Расширение никогда не был представлен на рассмотрение, чтобы увеличить. Как отмечено здесь, автор считает его полным.

Цикл Обработки Событий

в то время как libuv и Boost.Asio обеспечивает циклы событий, есть некоторые тонкие различия между два:

  • хотя libuv поддерживает несколько циклов событий, он не поддерживает выполнение одного цикла из нескольких потоков. По этой причине при использовании цикла по умолчанию (uv_default_loop()), а не создание нового цикла (uv_loop_new()), поскольку другой компонент может выполнять цикл по умолчанию.
  • импульс.Asio не имеет понятия цикла по умолчанию; all io_service их собственные петли, которые позволяют запускать несколько потоков. Чтобы поддержать этот импульс.Асио выполняет внутренний замок ценой производительность. Повышение.Редакция история указывает, что было несколько улучшений производительности для минимизации блокировки.

Threadpool

  • libuv обеспечивает threadpool через uv_queue_work. Размер threadpool является детализацией реализации и, по-видимому, не настраивается через API. Работа будет выполнена за пределами цикл событий и внутри threadpool. После завершения работы обработчик завершения будет помещен в очередь для запуска в цикле событий.
  • В То Время Как Boost.Asio не предоставляет threadpool,io_service может легко функционировать как один в результате io_service позволяет нескольким потокам вызывать run. Это возлагает ответственность за управление потоками и поведение на пользователя, как видно из этой пример.

продевать нитку и Синхронизация

  • libuv предоставляет абстракцию для потоков и типов синхронизации.
  • импульс.Нить предоставляет поток и типы синхронизации. Многие из этих типов соответствуют стандарту C++11, но также предоставляют некоторые расширения. В результате повышения.Asio позволяет нескольким потокам запускать один цикл событий, он обеспечивает strands как средство для создания последовательного вызова обработчиков событий без использование явных механизмов блокировки.

Операции С Файловой Системой

  • libuv предоставляет абстракцию для многих операций файловой системы. Одна функция в деятельность, и каждая деятельность может или быть одновременный преграждать или асинхронный. Если предусмотрен обратный вызов, то операция будет выполняться асинхронно во внутреннем пуле потоков. Если обратный вызов не предоставляется, то вызов будет синхронным блокировка.
  • импульс.Файловая система обеспечивает синхронные вызовы блокировки для многих операций файловой системы. Эти можно совместить с подталкиванием.Asio и threadpool для создания асинхронных операций файловой системы.

сеть

  • libuv поддерживает асинхронные операции с сокетами UDP и TCP, а также разрешение DNS. Разработчики приложений должны знать, что базовые файловые дескрипторы имеют значение неблокирующие. Поэтому собственные синхронные операции должны проверять возвращаемые значения и errno на EAGAIN или EWOULDBLOCK.
  • импульс.Asio немного богаче в своей сетевой поддержке. Кроме того, многие из функций сети libuv обеспечивает, повышение.Asio поддерживает SSL и ICMP сокеты. Кроме Того, Boost.Asio обеспечивает одновременную преграждать и одновременные non-преграждая деятельности, в дополнение к своим асинхронным деятельностям. Многочисленные свободные стоящие функции которые предоставьте общие операции более высокого уровня, такие как чтение заданного количества байтов или пока не будет прочитан указанный символ разделителя.

сигнал

  • libuv предоставляет абстракцию kill и обработка сигнала с его uv_signal_t тип и uv_signal_* операции. на данный момент, только цикл обработки событий по умолчанию поддерживает сигналы.
  • импульс.Asio не провоцирует абстракцию на kill, но signal_set_service обеспечивает обработку сигналов.

IPC


различия API

в то время как API различные на основе только языка, вот несколько ключевых различий:

Ассоциация операции и обработчика

Внутри Boost.Asio, существует взаимно однозначное сопоставление между операцией и обработчиком. Например, каждый async_write операция вызова WriteHandler раз. Это верно для многих операций и обработчиков libuv. Тем не менее, libuv uv_async_send поддерживает сопоставление "многие к одному". Несколько uv_async_send вызовы могут привести к the uv_async_cb вызывается один раз.

цепи вызовов против Watcher Loops

при работе с задачей, такой как чтение из потока/UDP, обработка сигналов или ожидание таймеров, Boost.Асинхронные цепочки вызовов Asio немного более явны. С libuv создается наблюдатель для обозначения интересов в конкретном событии. Затем запускается цикл для наблюдателя, где предоставляется обратный вызов. После получения события интересов, обратный вызов будет вызванный. С другой стороны, наддув.Asio требует, чтобы операция выдавалась каждый раз, когда приложение заинтересовано в обработке события.

чтобы проиллюстрировать эту разницу, вот асинхронный цикл чтения с Boost.Asio, где async_receive вызов будет выдан несколько раз:

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 );   --'
}    

и вот тот же пример с libuv, где handle_read вызывается каждый раз, когда наблюдатель замечает, что сокет имеет данные:

uv_read_start( socket, alloc_buffer, handle_read ); --.
                                                      |
    .-------------------------------------------------'
    |
    V
void handle_read( ... )
{
  fprintf( stdout, "got data\n" );
}

память Выделение

в результате асинхронных цепочек вызовов в Boost.Asio и наблюдатели в libuv, распределение памяти часто происходит в разное время. С наблюдателями libuv откладывает выделение до получения события, для обработки которого требуется память. Выделение выполняется посредством обратного вызова пользователя, вызываемого внутренним libuv, и переносит ответственность за освобождение приложения. С другой стороны, многие подталкивают.Операции Asio требуют выделения памяти перед выдачей асинхронной операции, например в случае buffer на async_read. Повышение.Асио не предусматривает null_buffers, который можно использовать для прослушивания события, позволяя приложениям откладывать выделение памяти до тех пор, пока не потребуется память.

эта разница в распределении памяти также представлена в bind->listen->accept петли. С libuv, uv_listen создает цикл событий, который вызовет обратный вызов пользователя, когда соединение будет готово к принятию. Это позволяет приложение отложить распределение клиента до подключения была предпринята. С другой стороны, наддув.Асио это listen только изменяет состояние acceptor. The async_accept прослушивает событие соединения и требует, чтобы одноранговый узел был выделен перед вызовом.


производительность

к сожалению, у меня нет конкретных контрольных цифр для сравнения libuv и Boost.Азио. Однако я наблюдал аналогичную производительность, используя библиотеки в приложениях реального и почти реального времени. Если нужны жесткие числа, libuv тест может служить отправной точкой.

кроме того, хотя профилирование должно выполняться для выявления фактических узких мест, помните о выделении памяти. Для libuv стратегия выделения памяти в основном ограничивается обратным вызовом распределителя. С другой стороны, наддув.API Asio не позволяет обратный вызов распределителя и вместо этого передает стратегию распределения приложению. Однако, обработчики/обратные вызовы в Boost.Asio может быть скопирован, выделен и освобожден. Повышение.Asio позволяет приложениям предоставлять настроить распределение памяти функции для реализации стратегии выделения памяти для обработчиков.


зрелость

импульс.Asio

разработка Asio восходит, по крайней мере, к октябрю 2004 года, и она была принята в Boost 1.35 22-MAR-2006 после прохождения 20-дневного экспертного обзора. Он также служил в качестве эталонной реализации и API для предложение сетевой библиотеки для TR2. Повышение.Asio имеет изрядное количество документация, хотя его полезность варьируется от пользователя к пользователю.

API также имеют довольно последовательное ощущение. Кроме того, асинхронные операции являются явными в имени операции. Например, accept одновременное блокирование и async_accept - это асинхронный. API предоставляет бесплатные функции для общей задачи ввода-вывода, например, чтение из потока до \r\n читать. Внимание также было уделено скрыть некоторые конкретные детали, такие как ip::address_v4::any() представляющий адрес" всех интерфейсов"0.0.0.0.

наконец, Boost 1.47 + обеспечивает отслеживание обработчик, что может оказаться полезным при отладке, а также поддержка C++11.

libuv

на основе на их графики на GitHub, узел.развитие Яш восходит к не менее февраль-2009, а развитие libuv датируется MAR-2011. The uvbook это отличное место для введения libuv. API является документирована в виде подробного заголовка, но все еще может использовать вклады в некоторых областях.

в целом, API довольно последователен и прост в использовании. Одна аномалия, которая может быть источником путаницы, заключается в том, что uv_tcp_listen создает цикл наблюдателя. Это отличается от других наблюдателей, которые обычно имеют uv_*_start и uv_*_stop пара функций для управления жизнью петли наблюдателя. Кроме того, некоторые из uv_fs_* операции имеют приличное количество аргументов (до 7). При синхронном и асинхронном поведении, определяемом на наличие обратного вызова (последний аргумент), видимость синхронного поведения может быть уменьшена.

наконец, быстрый взгляд на libuv история коммитов показывает, что разработчики очень активны.


Ok. У меня есть некоторый опыт использования обеих библиотек и я могу прояснить некоторые вещи.

во-первых, с концептуальной точки зрения эти библиотеки совершенно разные по дизайну. У них разные архитектуры, потому что они разного масштаба. Повышение.Asio-это большая сетевая библиотека, предназначенная для использования с протоколами TCP/UDP/ICMP, POSIX, SSL и так далее. Libuv-это просто слой для кросс-платформенной абстракции IOCP для узла.Яш, преимущественно. Так libuv это функционально подмножество Boost.Asio (общие характеристики только TCP / UDP сокеты потоков,таймеры). В этом случае мы можем сравнить эти библиотеки, используя только несколько критериев:

  1. интеграция с узлом.js-Libuv значительно лучше, потому что он предназначен для этого (мы можем полностью интегрировать его и использовать во всех аспектах, например, облако, например, windows azure). Но Asio также реализует почти ту же функциональность, что и в Node.приводимый в очередь событий в JS среды.
  2. IOCP Производительность-я не видел больших различий, потому что обе эти библиотеки абстрактные базовые API ОС. Но они делают это по-другому: Asio сильно использует функции C++, такие как шаблоны, а иногда и TMP. Libuv-это родная C-библиотека. Но тем не менее реализация МОК очень эффективна. Сокеты UDP в Asio недостаточно хороши, для них лучше использовать libuv.

    интеграция с новыми функциями c++: Asio лучше (Asio 1.51 широко использует асинхронную модель c++11, перемещение семантика, вариативные шаблоны).Что касается зрелости, Asio-более стабильный и зрелый проект с хорошей документацией (если сравнить его с описанием заголовков libuv), большим количеством информации через Интернет (видео-переговоры, блоги: http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=1 , etc.) и даже книги (не для профессионалов, но все же:http://en.highscore.de/cpp/boost/index.html). Libuv имеет только одну онлайн-книгу (но и хорошо) http://nikhilm.github.com/uvbook/index.html и несколько видео-разговоров, поэтому будет трудно узнать все секреты (в этой библиотеке их много). Для более конкретного обсуждения функций см. мои комментарии ниже.

В заключение я должен сказать, что все зависит от ваших целей, вашего проекта и того, что конкретно вы собираетесь делать.


одно огромное различие заключается в том, что автор Asio (Кристофер Кольхофф) готовит свою библиотеку для включения в стандартную библиотеку C++, см. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2175.pdf и http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4370.html