Câu trả lời:
Boost.Asio là một thư viện C ++ bắt đầu tập trung vào mạng, nhưng khả năng I / O không đồng bộ của nó đã được mở rộng sang các tài nguyên khác. Ngoài ra, với Boost.Asio là một phần của thư viện Boost, phạm vi của nó được thu hẹp một chút để tránh trùng lặp với các thư viện Boost khác. Ví dụ, Boost.Asio sẽ không cung cấp một trừu tượng chủ đề, như Boost.Thread đã cung cấp một.
Mặt khác, libuv là một thư viện C được thiết kế để có lớp nền tảng cho Node.js . Nó cung cấp một bản tóm tắt cho IOCP trên Windows, kqueue trên macOS và epoll trên Linux. Ngoài ra, có vẻ như phạm vi của nó đã tăng lên một chút để bao gồm các khái niệm trừu tượng và chức năng, chẳng hạn như các luồng, luồng, và giao tiếp giữa các luồng.
Tại cốt lõi của họ, mỗi thư viện cung cấp một vòng lặp sự kiện và các khả năng I / O không đồng bộ. Chúng có sự chồng chéo đối với một số tính năng cơ bản, chẳng hạn như bộ hẹn giờ, ổ cắm và các hoạt động không đồng bộ. libuv có phạm vi rộng hơn và cung cấp chức năng bổ sung, chẳng hạn như trừu tượng hóa luồng và đồng bộ hóa, hoạt động hệ thống tệp đồng bộ và không đồng bộ, quản lý quy trình, v.v. Ngược lại, các bề mặt tập trung mạng ban đầu của Boost.Asio, vì nó cung cấp một tập hợp mạng liên quan phong phú hơn các khả năng, chẳng hạn như ICMP, SSL, các hoạt động chặn và không chặn đồng bộ và các hoạt động cấp cao hơn cho các tác vụ thông thường, bao gồm đọc từ luồng cho đến khi nhận được dòng mới.
Dưới đây là so sánh ngắn gọn về một số tính năng chính. Vì các nhà phát triển sử dụng Boost.Asio thường có sẵn các thư viện Boost khác, tôi đã chọn xem xét các thư viện Boost bổ sung nếu chúng được cung cấp trực tiếp hoặc tầm thường để thực hiện.
libuv Boost Vòng lặp sự kiện: có Asio Threadpool: có Asio + Chủ đề Luồng: Chủ đề: có Chủ đề Đồng bộ hóa: có Chủ đề Hoạt động hệ thống tệp: Đồng bộ: có FileSystem Không đồng bộ: có Asio + Hệ thống tập tin Đồng hồ bấm giờ: có Asio Phân tán / Tập hợp I / O [1] : không có Asio Mạng: ICMP: không có Asio Độ phân giải DNS: Asio chỉ async SSL: không có Asio TCP: Asio chỉ async UDP: Asio chỉ async Tín hiệu: Xử lý: có Asio Gửi: có không IPC: Ổ cắm tên miền UNIX: có Asio Windows đặt tên ống: có Asio Quản lý quy trình: Tách rời: có Ống I / O: có Quá trình Sinh sản: có Quá trình Truy vấn hệ thống: CPU: có không Giao diện mạng: có không Cổng nối tiếp: không có TTY: có không Đang tải thư viện chia sẻ: có Tiện ích mở rộng [2]
2. Boost.Extension không bao giờ được gửi để đánh giá cho Boost. Như đã lưu ý ở đây , tác giả coi nó là hoàn chỉnh.
Trong khi cả libuv và Boost.Asio cung cấp các vòng lặp sự kiện, có một số khác biệt tinh tế giữa hai:
uv_default_loop()
), thay vì tạo một vòng lặp mới ( uv_loop_new()
), vì một thành phần khác có thể đang chạy vòng lặp mặc định.io_service
đều là các vòng lặp riêng cho phép chạy nhiều luồng. Để hỗ trợ Boost.Asio này thực hiện khóa nội bộ với chi phí của một số hiệu suất . Lịch sử sửa đổi của Boost.Asio chỉ ra rằng đã có một số cải tiến về hiệu suất để giảm thiểu việc khóa.uv_queue_work
. Kích thước luồng được cấu hình thông qua biến môi trường UV_THREADPOOL_SIZE
. Công việc sẽ được thực hiện bên ngoài vòng lặp sự kiện và trong chuỗi luồng. Khi công việc hoàn thành, trình xử lý hoàn thành sẽ được xếp hàng để chạy trong vòng lặp sự kiện.io_service
có thể dễ dàng hoạt động như một kết quả của io_service
việc cho phép nhiều luồng được gọi run
. Điều này đặt trách nhiệm quản lý luồng và hành vi cho người dùng, như có thể thấy trong ví dụ này .EAGAIN
hoặc EWOULDBLOCK
.kill
và xử lý tín hiệu với uv_signal_t
loại và uv_signal_*
hoạt động của nó .kill
, nhưng nó signal_set
cung cấp xử lý tín hiệu.uv_pipe_t
loại duy nhất .local::stream_protocol::socket
hoặc local::datagram_protocol::socket
, và windows::stream_handle
.Mặc dù các API khác nhau chỉ dựa trên ngôn ngữ, đây là một vài điểm khác biệt chính:
Trong Boost.Asio, có một ánh xạ một-một giữa thao tác và trình xử lý. Chẳng hạn, mỗi async_write
thao tác sẽ gọi WriteHandler một lần. Điều này đúng với nhiều hoạt động libuv và xử lý. Tuy nhiên, libuv's uv_async_send
hỗ trợ ánh xạ nhiều-một. Nhiều uv_async_send
cuộc gọi có thể dẫn đến việc uv_async_cb được gọi một lần.
Khi xử lý tác vụ, chẳng hạn như đọc từ luồng / UDP, xử lý tín hiệu hoặc chờ trên bộ hẹn giờ, chuỗi cuộc gọi không đồng bộ của Boost.Asio rõ ràng hơn một chút. Với libuv, một người theo dõi được tạo ra để chỉ định lợi ích trong một sự kiện cụ thể. Một vòng lặp sau đó được bắt đầu cho người theo dõi, nơi cung cấp một cuộc gọi lại. Khi nhận được sự kiện quan tâm, cuộc gọi lại sẽ được gọi. Mặt khác, Boost.Asio yêu cầu một hoạt động được ban hành mỗi khi ứng dụng quan tâm đến việc xử lý sự kiện.
Để giúp minh họa sự khác biệt này, đây là một vòng lặp đọc không đồng bộ với Boost.Asio, nơi async_receive
cuộc gọi sẽ được phát ra nhiều lần:
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 ); --'
}
Và đây là ví dụ tương tự với libuv, nơi handle_read
được gọi mỗi khi người quan sát quan sát thấy ổ cắm có dữ liệu:
uv_read_start( socket, alloc_buffer, handle_read ); --.
|
.-------------------------------------------------'
|
V
void handle_read( ... )
{
fprintf( stdout, "got data\n" );
}
Là kết quả của chuỗi cuộc gọi không đồng bộ trong Boost.Asio và người theo dõi trong libuv, việc cấp phát bộ nhớ thường xảy ra ở các thời điểm khác nhau. Với người theo dõi, libuv trì hoãn phân bổ cho đến sau khi nó nhận được một sự kiện đòi hỏi bộ nhớ để xử lý. Việc phân bổ được thực hiện thông qua một cuộc gọi lại của người dùng, gọi nội bộ đến libuv và trì hoãn trách nhiệm phân bổ của ứng dụng. Mặt khác, nhiều hoạt động Boost.Asio yêu cầu bộ nhớ được phân bổ trước khi ban hành hoạt động không đồng bộ, chẳng hạn như trường hợp buffer
for async_read
. Boost.Asio cung cấp null_buffers
, có thể được sử dụng để lắng nghe một sự kiện, cho phép các ứng dụng trì hoãn việc cấp phát bộ nhớ cho đến khi cần bộ nhớ, mặc dù điều này không được chấp nhận.
Sự khác biệt phân bổ bộ nhớ này cũng thể hiện chính nó trong bind->listen->accept
vòng lặp. Với libuv, uv_listen
tạo một vòng lặp sự kiện sẽ gọi lại cuộc gọi lại của người dùng khi một kết nối đã sẵn sàng để được chấp nhận. Điều này cho phép ứng dụng trì hoãn việc phân bổ máy khách cho đến khi kết nối được thực hiện. Mặt khác, Boost.Asio listen
chỉ thay đổi trạng thái của acceptor
. Việc async_accept
lắng nghe sự kiện kết nối và yêu cầu phân bổ ngang hàng trước khi được gọi.
Thật không may, tôi không có bất kỳ số điểm chuẩn cụ thể nào để so sánh libuv và Boost.Asio. Tuy nhiên, tôi đã quan sát hiệu suất tương tự bằng cách sử dụng các thư viện trong các ứng dụng thời gian thực và gần thời gian thực. Nếu số cứng là mong muốn, kiểm tra điểm chuẩn của libuv có thể đóng vai trò là điểm bắt đầu.
Ngoài ra, trong khi định hình nên được thực hiện để xác định các tắc nghẽn thực tế, hãy lưu ý đến việc phân bổ bộ nhớ. Đối với libuv, chiến lược cấp phát bộ nhớ chủ yếu giới hạn trong cuộc gọi lại cấp phát. Mặt khác, API của Boost.Asio không cho phép gọi lại phân bổ, và thay vào đó đẩy chiến lược phân bổ cho ứng dụng. Tuy nhiên, các trình xử lý / gọi lại trong Boost.Asio có thể được sao chép, phân bổ và giải phóng. Boost.Asio cho phép các ứng dụng cung cấp các chức năng cấp phát bộ nhớ tùy chỉnh để thực hiện chiến lược phân bổ bộ nhớ cho các trình xử lý.
Sự phát triển của Asio bắt đầu từ ít nhất là tháng 10 năm 2004 và nó đã được chấp nhận vào Boost 1.35 vào ngày 22 tháng 3 năm 2006 sau khi trải qua đánh giá ngang hàng 20 ngày. Nó cũng được dùng làm triển khai tham chiếu và API cho Đề xuất thư viện mạng cho TR2 . Boost.Asio có số lượng tài liệu khá lớn , mặc dù tính hữu dụng của nó thay đổi tùy theo người dùng.
API cũng có một cảm giác khá nhất quán. Ngoài ra, các hoạt động không đồng bộ được thể hiện rõ ràng trong tên của hoạt động. Ví dụ, accept
là chặn đồng bộ và async_accept
không đồng bộ. API cung cấp các hàm miễn phí cho tác vụ I / O chung, ví dụ, đọc từ luồng cho đến khi \r\n
đọc. Sự chú ý cũng đã được đưa ra để ẩn một số chi tiết cụ thể của mạng, chẳng hạn như ip::address_v4::any()
đại diện cho địa chỉ "tất cả giao diện" của 0.0.0.0
.
Cuối cùng, Boost 1.47+ cung cấp tính năng theo dõi trình xử lý , có thể chứng minh là hữu ích khi gỡ lỗi, cũng như hỗ trợ C ++ 11.
Dựa trên biểu đồ github của họ, quá trình phát triển của Node.js bắt đầu từ ít nhất FEB-2009 và ngày phát triển của libuv đến tháng 3 năm 2011 . Các uvbook là một nơi tuyệt vời để giới thiệu libuv. Tài liệu API có ở đây .
Nhìn chung, API khá nhất quán và dễ sử dụng. Một điều bất thường có thể là một nguồn gây nhầm lẫn là uv_tcp_listen
tạo ra một vòng lặp theo dõi. Điều này khác với các đồng hồ khác thường có một uv_*_start
và uv_*_stop
cặp chức năng để kiểm soát vòng đời của vòng theo dõi. Ngoài ra, một số uv_fs_*
thao tác có số lượng đối số khá lớn (tối đa 7). Với hành vi đồng bộ và không đồng bộ được xác định dựa trên sự hiện diện của một cuộc gọi lại (đối số cuối cùng), khả năng hiển thị của hành vi đồng bộ có thể bị giảm đi.
Cuối cùng, lướt qua lịch sử cam kết libuv cho thấy các nhà phát triển rất tích cực.
uv_async_send
cuộc gọi và xử lý tất cả chúng với một cuộc gọi lại. Nó được ghi lại ở đây . Ngoài ra, cảm ơn mọi người.
Đồng ý. Tôi có một số kinh nghiệm trong việc sử dụng cả hai thư viện và có thể làm rõ một số điều.
Đầu tiên, từ quan điểm khái niệm, các thư viện này khá khác nhau về thiết kế. Chúng có kiến trúc khác nhau, bởi vì chúng có quy mô khác nhau. Boost.Asio là một thư viện mạng lớn nhằm mục đích sử dụng với các giao thức TCP / UDP / ICMP, POSIX, SSL, v.v. Libuv chỉ là một lớp để trừu tượng hóa đa nền tảng của IOCP cho Node.js, chủ yếu. Vì vậy, libuv về mặt chức năng là một tập hợp con của Boost.Asio (tính năng phổ biến chỉ có các luồng, bộ định thời TCP / UDP). Trong trường hợp đó, chúng ta có thể so sánh các thư viện này chỉ bằng một vài tiêu chí:
Tích hợp với các tính năng mới của C ++: Asio tốt hơn (Asio 1.51 sử dụng rộng rãi mô hình không đồng bộ C ++ 11, ngữ nghĩa di chuyển, mẫu biến đổi). Về mặt trưởng thành, Asio là một dự án ổn định và trưởng thành hơn với tài liệu tốt (nếu so sánh nó với libuv mô tả tiêu đề), rất nhiều thông tin trên Internet (video nói chuyện, blog: http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg = 1 , v.v.) và thậm chí cả sách (không dành cho chuyên gia nhưng tuy nhiên: http://en.highscore.de/cpp/boost/index.html ). Libuv chỉ có một cuốn sách trực tuyến (nhưng cũng tốt) http://nikhilm.github.com/uvbook/index.htmlvà một vài cuộc nói chuyện bằng video, vì vậy sẽ rất khó để biết tất cả các bí mật (thư viện này có rất nhiều trong số đó). Để thảo luận cụ thể hơn về các chức năng xem ý kiến của tôi dưới đây.
Để kết luận, tôi nên nói rằng tất cả phụ thuộc vào mục đích của bạn, dự án của bạn và cụ thể bạn dự định làm gì.
Một sự khác biệt lớn là tác giả của Asio (Christopher Kohlhoff) đang chuẩn bị cho thư viện của mình để đưa vào Thư viện chuẩn C ++, xem http://www.open-std.org/jtc1/sc22/wg21/docs/ con 2007 / n2175 .pdf và http://www.open-std.org/jtc1/sc22/wg21/docs/ con / 2015 / n4370.html
Thêm trạng thái tính di động: Khi đăng câu trả lời này và theo nỗ lực của riêng tôi: