Як libuv порівнюється з Boost / ASIO?


239

Мене зацікавлять такі аспекти, як:

  • сфера / особливості
  • виконання
  • зрілість

20
Давайте повернемося до цього питання і отримаємо хороші відповіді!
В'єт

\ o / .. сподіваємось, ми отримаємо кілька проникливих відповідей!
oberstet

Відповіді:


493

Область застосування

Boost.Asio - це бібліотека C ++, яка почалася з упором на мережу, але її асинхронні можливості вводу / виводу були поширені на інші ресурси. Крім того, оскільки Boost.Asio є частиною бібліотек Boost, його обсяг трохи звужується, щоб запобігти дублюванню з іншими бібліотеками Boost. Наприклад, Boost.Asio не забезпечить абстрагування потоку, оскільки Boost.Thread вже забезпечує його.

З іншого боку, libuv бібліотека C призначена для платформи шар для Node.js . Він забезпечує абстракцію IOCP в Windows, kqueue на macOS та epoll в Linux. Крім того, схоже, що сфера його застосування трохи збільшилася, включаючи абстракції та функціональні можливості, такі як потоки, потокові пули та комунікації між потоками.

У своїй основі кожна бібліотека забезпечує цикл подій та асинхронні можливості вводу / виводу. Вони перекриваються деякими основними функціями, такими як таймери, сокети та асинхронні операції. libuv має більш широку сферу застосування та забезпечує додаткову функціональність, таку як абстракції потоків та синхронізації, операції синхронної та асинхронної файлової системи, управління процесами тощо. такі можливості, як ICMP, SSL, синхронне блокування та неблокуючі операції та операції вищого рівня для звичайних завдань, включаючи зчитування з потоку до отримання нового рядка.


Список функцій

Ось коротке побічне порівняння деяких основних особливостей. Оскільки розробники, які використовують Boost.Asio, часто мають інші бібліотеки Boost, я вирішив розглянути додаткові бібліотеки Boost, якщо вони безпосередньо надані або тривіальні для реалізації.

                         libuv Boost
Петля події: так Асіо
Нитка: так Асіо + Нитки
Нитка:              
  Нитки: так Нитки
  Синхронізація: так Нитки
Операції з файловою системою:
  Синхронна: так FileSystem
  Асинхронна: так, файлова система Asio +
Таймери: так Асіо
Scatter / Gather I / O [1] : немає Асіо
Мережа:
  ICMP: немає Asio
  Роздільна здатність DNS: Asio тільки для Asio
  SSL: немає Асіо
  TCP: Asio тільки для Async
  UDP: Asio тільки для Async
Сигнал:
  Поводження: так Асіо
  Відправлення: так ні
IPC:
  Розетки домену UNIX: так Asio
  Труба з назвою Windows: так Asio
Управління процесами:
  Від'єднання: так Процес
  Труба вводу / виводу: так Процес
  Нерест: так Процес
Системні запити:
  ЦП: так ні
  Мережевий інтерфейс: так, ні
Серійні порти: ні, так
TTY: так ні
Завантаження загальної бібліотеки: так, розширення [2]

1. Розсіювання / Збір вводу / виводу .

2. Boost.Extension ніколи не надсилався на розгляд Boost. Як зазначалося тут , автор вважає це завершеним.

Петля події

Хоча і libuv і Boost.Asio надають петлі подій, є деякі тонкі відмінності між ними:

  • Хоча libuv підтримує декілька циклів подій, він не підтримує виконання одного циклу з декількох потоків. З цієї причини потрібно бути обережним при використанні циклу за замовчуванням ( uv_default_loop()), а не створювати новий цикл ( uv_loop_new()), оскільки інший компонент може запускати цикл за замовчуванням.
  • Boost.Asio не має поняття циклу за замовчуванням; всі io_serviceце власні петлі, які дозволяють запускати декілька потоків. Для підтримки цього Boost.Asio виконує внутрішнє блокування ціною деякої продуктивності . Перегляд Boost.Asio в історії вказує на те, що були деякі поліпшення продуктивності для мінімізації блокування.

Нитка

  • libuv's забезпечує нитку наскрізь uv_queue_work. Розмір нитки каналів може бути налаштований за допомогою змінної середовища UV_THREADPOOL_SIZE. Робота буде виконана за межами циклу подій та всередині нитки. Після завершення роботи обробник завершення буде поставлений у чергу для запуску в циклі подій.
  • У той час як Boost.Asio не забезпечує пучок потоків, він io_serviceможе легко функціонувати як один в результаті, io_serviceдозволяючи викликати кілька потоків run. Це покладає на користувача відповідальність управління потоками та поведінку, як це видно в цьому прикладі.

Нитки та синхронізація

  • libuv забезпечує абстрагування потоків та типів синхронізації.
  • Boost.Thread забезпечує потоки та типи синхронізації. Багато з цих типів уважно дотримуються стандарту C ++ 11, але також надають деякі розширення. В результаті Boost.Asio, що дозволяє декільком потокам запускати один цикл подій, він забезпечує нитки як засіб для створення послідовного виклику обробників подій без використання явних механізмів блокування.

Операції з файловою системою

  • libuv забезпечує абстракцію багатьох операцій з файловою системою. Існує одна функція на одну операцію, і кожна операція може бути або синхронним блокуванням, або асинхронною. Якщо надається зворотний дзвінок, то операція буде виконуватися асинхронно всередині внутрішнього потоку. Якщо зворотний дзвінок не надається, то виклик буде синхронним блокуванням.
  • Boost.Filesystem забезпечує синхронне блокування дзвінків для багатьох операцій з файловою системою. Вони можуть поєднуватися з Boost.Asio і потоковим пулом для створення асинхронних операцій з файловою системою.

Мережі

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

Сигнал

  • libuv забезпечує абстракцію killта обробку сигналу своїм uv_signal_tтипом та uv_signal_*операціями.
  • Boost.Asio не надає абстракції kill, але signal_setзабезпечує обробку сигналів.

IPC


Відмінності API

Хоча API відрізняються лише мовою, тут є кілька ключових відмінностей:

Асоціація з експлуатації та обробки даних

У Boost.Asio існує відображення один на один між операцією та обробником. Наприклад, кожна async_writeоперація буде викликати WriteHandler один раз. Це справедливо для багатьох операцій libuv та обробників. Однак, libuv uv_async_sendпідтримує багатозначне відображення. Багаторазові uv_async_sendдзвінки можуть призвести до виклику uv_async_cb один раз.

Дзвінки ланцюга проти циклів спостерігачів

При вирішенні завдань, таких як зчитування з потоку / UDP, обробка сигналів або очікування таймерів, асинхронні ланцюги викликів Boost.Asio дещо чіткіші. За допомогою libuv створюється спостерігач для позначення інтересів у певній події. Потім запускається цикл для спостерігача, де надається зворотний дзвінок. Після отримання події інтересів, зворотний дзвінок буде викликаний. З іншого боку, Boost.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, і відкладає відповідальність за місцерозташування програми. З іншого боку, для багатьох операцій Boost.Asio потрібно виділити пам'ять перед видачею асинхронної операції, як, наприклад, bufferдля async_read. Boost.Asio передбачає null_buffers, що можна використовувати для прослуховування події, дозволяючи програмам відкладати розподіл пам’яті до тих пір, поки не потрібна пам'ять, хоча ця застаріла.

Ця різниця розподілу пам'яті також відображається в bind->listen->acceptциклі. За допомогою libuv uv_listenстворює цикл подій, який викликатиме зворотний виклик користувача, коли з'єднання готове прийняти. Це дозволяє програмі відкласти розподіл клієнта до спроби з'єднання. З іншого боку, Boost.Asio listenлише змінює стан acceptor. Він async_acceptпрослуховує подію з'єднання та вимагає, щоб перед тим, як викликати, привласнювати однорангового.


Продуктивність

На жаль, у мене немає конкретних орієнтирів для порівняння libuv та Boost.Asio. Однак я спостерігав подібну ефективність використання бібліотек у додатках у режимі реального часу та майже в реальному часі. Якщо потрібні важкі цифри, тест еталону libuv може послужити відправною точкою.

Крім того, хоча профілювання має здійснюватися для виявлення фактичних вузьких місць, пам’ятайте про розподіл пам’яті. Для libuv стратегія розподілу пам'яті в основному обмежується зворотним зв'язком алокатора. З іншого боку, API Boost.Asio не дозволяє зворотній зв'язок алокатора, а натомість підштовхує стратегію розподілу до програми. Однак обробники / зворотні дзвінки в Boost.Asio можуть бути скопійовані, виділені та розміщені. Boost.Asio дозволяє програмам надавати власні функції розподілу пам'яті для реалізації стратегії розподілу пам'яті для обробників.


Зрілість

Boost.Asio

Розробка Asio починається щонайменше з OCT-2004, і вона була прийнята в Boost 1.35 22-го березня 2006 року після 20-денного експертного огляду. Він також слугував еталонною реалізацією та API для створення мережевої бібліотеки для TR2 . Boost.Asio має досить багато документації , хоча її корисність залежить від користувача до користувача.

API також має досить стійке враження. Крім того, асинхронні операції явні у назві операції. Наприклад, acceptє синхронним блокуванням і async_acceptє асинхронним. API надає безкоштовні функції для загальної задачі вводу / виводу, наприклад, зчитування з потоку, поки не \r\nбуде прочитано a . Також приділялася увага приховувати деякі конкретні мережеві деталі, наприклад ip::address_v4::any()представлення адреси "всіх інтерфейсів" 0.0.0.0.

Нарешті, Boost 1.47+ забезпечує відстеження обробників , що може виявитися корисним при налагодженні, а також підтримку C ++ 11.

libuv

На основі їхніх графіків github, розробка Node.js сягає щонайменше FEB-2009 , а розробка libuv датується MAR-2011 . Uvbook є відмінним місцем для введення libuv. Документація API тут .

Загалом, API досить стійкий і простий у використанні. Одна аномалія, яка може бути джерелом плутанини, - це те, що uv_tcp_listenстворюється цикл спостерігачів. Це відрізняється від інших спостерігачів, які, як правило, мають uv_*_startта uv_*_stopпару функцій для контролю життя петлі. Також деякі uv_fs_*операції мають пристойну кількість аргументів (до 7). Якщо синхронна та асинхронна поведінка визначається за наявністю зворотного виклику (останній аргумент), видимість синхронної поведінки може бути зменшена.

Нарешті, швидкий погляд на історію фіксації libuv показує, що розробники дуже активні.


2
Спасибі людино! Чудова відповідь! Я не можу придумати нічого більш вичерпного :)
В'єт

1
Дуже задоволений відповіддю, я нагороджую вас щедротою :) Нехай ТА вирішить найкращу відповідь для себе.
В'єтнат

28
Неймовірна відповідь. Це охоплює як зображення високого рівня, так і конкретні, важливі відмінності в деталях (наприклад, нарізка / поділка). Велике спасибі!
оберстет

1
@oberstet: Ні. Я оновив відповідь, щоб зазначити, що більшість операцій libuv проходять однозначно. Однак libuv може накопичувати декілька uv_async_sendдзвінків і обробляти їх усіма одним зворотним зворотом . Це задокументовано тут . Також дякую всім.
Таннер Сансбері

2
Внутрішнє блокування циклу подій у Boost.Asio виглядає страшно з точки зору продуктивності. Як це може мати подібні показники роботи без замка libuv? Можливо, додавання попереджувальної заяви до розділу про ефективність може бути корисним.
zeodtr

46

Гаразд. Я маю певний досвід використання обох бібліотек і можу прояснити деякі речі.

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

  1. Інтеграція з Node.js - Libuv значно краща, оскільки вона спрямована на це (ми можемо повністю інтегрувати її та використовувати у всіх аспектах, наприклад, хмара, наприклад, лазур Windows). Але Asio також реалізує майже таку ж функціональність, як і в середовищі, керованій чергою подій Node.js.
  2. Продуктивність IOCP - я не міг бачити великих відмінностей, оскільки обидві ці бібліотеки абстрактно лежать в основі API API. Але вони роблять це по-іншому: Asio активно використовує функції C ++, такі як шаблони, а іноді і TMP. Libuv - це рідна С-бібліотека. Але, тим не менш, реалізація IOCP Asio дуже ефективна. 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 тощо) і навіть книги (не для професіоналів, але все-таки: http://en.highscore.de/cpp/boost/index.html ). У Лібува є лише одна онлайн-книга (але також хороша) http://nikhilm.github.com/uvbook/index.htmlі кілька відеозвернень, тож важко буде дізнатись усі секрети (у цій бібліотеці їх дуже багато). Для більш конкретного обговорення функцій дивіться мої коментарі нижче.

На закінчення я повинен сказати, що все залежить від ваших цілей, вашого проекту та того, що конкретно ви маєте намір зробити.


11
Важливе значення має ваша технічна майстерність та досвід. Добрі вітання з кубинця.
dsign

2
Я погоджуюся з усіма вашими пунктами, крім документації Asio. Офіційна документація не справляється з цією чудовою бібліотекою. Існує купа інших документів і підказок із автором, який я вважаю дуже корисним. І я не натрапив на книгу для Асіо. Чи можете ви пов’язати це у своїй відповіді? Це буде дуже корисно.
Вікас

@vikas Так, я погоджуюся, що документація погана, а іноді суперечлива, але порівняно з libuv, це приємно для початку. Що стосується книг, я редагую свою відповідь, але, думаю, ви бачили її раніше (на жаль, не існує книги, повністю присвяченої Boost - лише розкиданої інформація)
Олександр Караберов

Що ви маєте на увазі під "таким чином, libuv функціонально є підмножиною Boost.Asio (TCP / UDP / Sockets and thread)"? Відповідно до TOC nikhilm.github.com/uvbook/index.html libuv має більш широке застосування, а потім boost :: asio.
Сергій Никулов

7
@AlexanderKaraberov Ви могли б розширити проблеми ASIO, пов'язані з UDP?
Бруно Мартінез


2

Додавання статусу переносимості: На момент опублікування цієї відповіді та відповідно до моїх власних спроб:

  • Boost.ASIO не має офіційної підтримки для iOS та Android, наприклад, його система збірки не працює для iOS поза коробкою.
  • libuv легко створює для iOS та Android, з офіційною підтримкою Android прямо у своїх документах . Мій власний загальний сценарій збирання iOS для проектів на основі Autotools працює без проблем.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.