Відповіді:
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 надають петлі подій, є деякі тонкі відмінності між ними:
uv_default_loop()
), а не створювати новий цикл ( uv_loop_new()
), оскільки інший компонент може запускати цикл за замовчуванням.io_service
це власні петлі, які дозволяють запускати декілька потоків. Для підтримки цього Boost.Asio виконує внутрішнє блокування ціною деякої продуктивності . Перегляд Boost.Asio в історії вказує на те, що були деякі поліпшення продуктивності для мінімізації блокування.uv_queue_work
. Розмір нитки каналів може бути налаштований за допомогою змінної середовища UV_THREADPOOL_SIZE
. Робота буде виконана за межами циклу подій та всередині нитки. Після завершення роботи обробник завершення буде поставлений у чергу для запуску в циклі подій.io_service
може легко функціонувати як один в результаті, io_service
дозволяючи викликати кілька потоків run
. Це покладає на користувача відповідальність управління потоками та поведінку, як це видно в цьому прикладі.EAGAIN
або EWOULDBLOCK
.kill
та обробку сигналу своїм uv_signal_t
типом та uv_signal_*
операціями.kill
, але signal_set
забезпечує обробку сигналів.uv_pipe_t
тип.local::stream_protocol::socket
або local::datagram_protocol::socket
, і windows::stream_handle
.Хоча 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 дозволяє програмам надавати власні функції розподілу пам'яті для реалізації стратегії розподілу пам'яті для обробників.
Розробка 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.
На основі їхніх графіків github, розробка Node.js сягає щонайменше FEB-2009 , а розробка libuv датується MAR-2011 . Uvbook є відмінним місцем для введення libuv. Документація API тут .
Загалом, API досить стійкий і простий у використанні. Одна аномалія, яка може бути джерелом плутанини, - це те, що uv_tcp_listen
створюється цикл спостерігачів. Це відрізняється від інших спостерігачів, які, як правило, мають uv_*_start
та uv_*_stop
пару функцій для контролю життя петлі. Також деякі uv_fs_*
операції мають пристойну кількість аргументів (до 7). Якщо синхронна та асинхронна поведінка визначається за наявністю зворотного виклику (останній аргумент), видимість синхронної поведінки може бути зменшена.
Нарешті, швидкий погляд на історію фіксації libuv показує, що розробники дуже активні.
uv_async_send
дзвінків і обробляти їх усіма одним зворотним зворотом . Це задокументовано тут . Також дякую всім.
Гаразд. Я маю певний досвід використання обох бібліотек і можу прояснити деякі речі.
По-перше, з концептуальної точки зору ці бібліотеки відрізняються дизайном. Вони мають різні архітектури, тому що вони різного масштабу. Boost.Asio - це велика мережева бібліотека, призначена для використання з протоколами TCP / UDP / ICMP, POSIX, SSL тощо. Libuv - це лише шар для міжплатформової абстракції IOCP для Node.js, переважно. Таким чином, libuv є функціонально підмножиною Boost.Asio (загальні риси лише ниток TCP / UDP Sockets, таймерів). У цьому випадку ми можемо порівняти ці бібліотеки, використовуючи лише декілька критеріїв:
Інтеграція з новими функціями 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і кілька відеозвернень, тож важко буде дізнатись усі секрети (у цій бібліотеці їх дуже багато). Для більш конкретного обговорення функцій дивіться мої коментарі нижче.
На закінчення я повинен сказати, що все залежить від ваших цілей, вашого проекту та того, що конкретно ви маєте намір зробити.
Величезна різниця полягає в тому, що автор Асіо (Крістофер Колхофф) доглядає за його бібліотекою для включення до стандартної бібліотеки 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
Додавання статусу переносимості: На момент опублікування цієї відповіді та відповідно до моїх власних спроб: