Làm thế nào để libuv so sánh với Boost / ASIO?


239

Tôi quan tâm đến các khía cạnh như:

  • phạm vi / tính năng
  • hiệu suất
  • trưởng thành

20
Hãy trả lại câu hỏi này và nhận được câu trả lời tốt!
Việt

\ o / .. hy vọng chúng tôi nhận được một số câu trả lời sâu sắc!
oberstet

Câu trả lời:


493

Phạm vi

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.


Danh sách tính năng

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]

1. Scatter / Thu thập I / O .

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.

Vòng lặp sự kiện

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:

  • Mặc dù libuv hỗ trợ nhiều vòng lặp sự kiện, nhưng nó không hỗ trợ chạy cùng một vòng lặp từ nhiều luồng. Vì lý do này, cần thận trọng khi sử dụng vòng lặp mặc định ( 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.
  • Boost.Asio không có khái niệm về một vòng lặp mặc định; tất cả 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.

Chủ đề

  • libuv's cung cấp một luồng thông qua 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.
  • Mặc dù Boost.Asio không cung cấp một luồng, nhưng nó io_servicecó thể dễ dàng hoạt động như một kết quả của io_serviceviệ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 .

Luồng và đồng bộ hóa

  • libuv cung cấp một sự trừu tượng cho các chủ đề và các loại đồng bộ hóa.
  • Boost.Thread cung cấp một loại chủ đề và đồng bộ hóa. Nhiều loại trong số này theo sát tiêu chuẩn C ++ 11, nhưng cũng cung cấp một số phần mở rộng. Kết quả của Boost.Asio cho phép nhiều luồng chạy một vòng sự kiện, nó cung cấp các chuỗi như một phương tiện để tạo ra một lệnh gọi tuần tự của các trình xử lý sự kiện mà không cần sử dụng các cơ chế khóa rõ ràng.

Hoạt động hệ thống tập tin

  • libuv cung cấp một sự trừu tượng cho nhiều hoạt động hệ thống tập tin. Có một chức năng cho mỗi hoạt động và mỗi hoạt động có thể là chặn đồng bộ hoặc không đồng bộ. Nếu một cuộc gọi lại được cung cấp, thì hoạt động sẽ được thực hiện không đồng bộ trong một luồng nội bộ. Nếu một cuộc gọi lại không được cung cấp, thì cuộc gọi sẽ bị chặn đồng bộ.
  • Boost.Filesystem cung cấp các cuộc gọi chặn đồng bộ cho nhiều hoạt động của hệ thống tệp. Chúng có thể được kết hợp với Boost.Asio và một luồng để tạo các hoạt động hệ thống tệp không đồng bộ.

Mạng

  • libuv hỗ trợ các hoạt động không đồng bộ trên các ổ cắm UDP và TCP, cũng như độ phân giải DNS. Các nhà phát triển ứng dụng nên biết rằng các bộ mô tả tệp bên dưới được đặt thành không chặn. Do đó, các hoạt động đồng bộ riêng nên kiểm tra các giá trị trả về và errno cho EAGAINhoặc EWOULDBLOCK.
  • Boost.Asio phong phú hơn một chút trong hỗ trợ mạng. Ngoài ra, nhiều tính năng mà mạng libuv cung cấp, Boost.Asio hỗ trợ các ổ cắm SSL và ICMP. Hơn nữa, Boost.Asio cung cấp các hoạt động chặn đồng bộ và không chặn đồng bộ, ngoài các hoạt động không đồng bộ của nó. Có rất nhiều hàm đứng miễn phí cung cấp các hoạt động cấp cao hơn phổ biến, chẳng hạn như đọc một lượng byte được đặt hoặc cho đến khi một ký tự phân cách được chỉ định được đọc.

Tín hiệu

  • libuv cung cấp một sự trừu tượng killvà xử lý tín hiệu với uv_signal_tloại và uv_signal_*hoạt động của nó .
  • Boost.Asio không chứng minh sự trừu tượng hóa kill, nhưng nó signal_setcung cấp xử lý tín hiệu.

IPC


Sự khác biệt API

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:

Hiệp hội vận hành và xử lý

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_writethao 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_sendhỗ trợ ánh xạ nhiều-một. Nhiều uv_async_sendcuộc gọi có thể dẫn đến việc uv_async_cb được gọi một lần.

Chuỗi cuộc gọi so với vòng lặp Watcher

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_receivecuộ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" );
}

Cấp phát bộ nhớ

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 bufferfor 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->acceptvòng lặp. Với libuv, uv_listentạ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 listenchỉ thay đổi trạng thái của acceptor. Việc async_acceptlắ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.


Hiệu suất

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ý.


Trưởng thành

Boost.Asio

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ụ, acceptlà chặn đồng bộ và async_acceptkhô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.

libuv

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_listentạ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_*_startuv_*_stopcặ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.


2
Cảm ơn người đàn ông! Câu trả lời chính xác! Tôi không thể nghĩ bất cứ điều gì toàn diện hơn :)
Việt Nam

1
Rất hài lòng với câu trả lời, tôi thưởng cho bạn tiền thưởng :) Hãy để SO quyết định câu trả lời tốt nhất cho mình.
Việt

28
Câu trả lời đáng kinh ngạc. Điều này bao gồm cả hình ảnh cấp cao, cũng như sự khác biệt cụ thể, quan trọng về chi tiết (như luồng / sự kiện). Cảm ơn rât nhiều!
oberstet

1
@oberstet: Không. Tôi đã cập nhật câu trả lời để đề cập rằng hầu hết các hoạt động của libuv là một đối một. Tuy nhiên, libuv có thể tích lũy nhiều uv_async_sendcuộ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.
Tanner Sansbury

2
Khóa nội bộ trên vòng lặp sự kiện trên Boost.Asio trông đáng sợ từ quan điểm hiệu suất. Làm thế nào nó có thể có hiệu suất tương tự như libuv không khóa? Có lẽ việc thêm một tuyên bố cảnh báo trên phần hiệu suất có thể hữu ích.
zeodtr

46

Đồ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í:

  1. Tích hợp với Node.js - Libuv tốt hơn đáng kể vì nó nhằm mục đích này (chúng tôi hoàn toàn có thể tích hợp nó và sử dụng trong tất cả các khía cạnh, ví dụ: đám mây, ví dụ như windows azure). Nhưng Asio cũng thực hiện gần như chức năng tương tự như trong môi trường điều khiển hàng đợi sự kiện Node.js.
  2. Hiệu suất IOCP - Tôi không thể thấy sự khác biệt lớn, bởi vì cả hai thư viện này đều trừu tượng API hệ điều hành. Nhưng họ làm điều đó theo một cách khác: Asio sử dụng rất nhiều tính năng của C ++ như các mẫu và đôi khi là TMP. Libuv là một thư viện C bản địa. Nhưng tuy nhiên Asio hiện thực hóa IOCP rất hiệu quả. Ổ cắm UDP trong Asio không đủ tốt, tốt hơn là sử dụng libuv cho chúng.

    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ì.


11
Điều quan trọng là kỹ năng và kinh nghiệm kỹ thuật của bạn. Lời chào tốt đẹp từ một người Cuba.
DSign

2
Tôi đồng ý với tất cả các điểm của bạn ngoại trừ tài liệu của Asio. Các tài liệu chính thức không làm bất kỳ công lý cho thư viện tuyệt vời này. Có một loạt các tài liệu khác và một bài nói chuyện từ tác giả mà tôi thấy rất hữu ích. Và tôi đã không bắt gặp một cuốn sách cho Asio. Bạn có thể liên kết mà trong câu trả lời của bạn? Nó sẽ rất có ích.
Vikas

@vikas Có Tôi đồng ý tài liệu kém và đôi khi mâu thuẫn nhưng so với libuv thì thật tuyệt khi bắt đầu. Đối với sách tôi chỉnh sửa câu trả lời của tôi nhưng tôi nghĩ bạn đã thấy nó trước đây (tiếc là không có cuốn sách nào dành riêng cho Boost - chỉ phân tán thông tin)
Oleksandr Karaberov

Ý của bạn là gì "Vì vậy, libuv về mặt chức năng là một tập hợp con của Boost.Asio (TCP / UDP / Sockets và thread)"? Theo TOC nikhilm.github.com/uvbook/index.html libuv có ứng dụng rộng hơn thì boost :: asio.
Sergei Nikulov

7
@AlexanderKaraberov bạn có thể mở rộng về các vấn đề mà ASIO gặp phải với UDP không?
Bruno Martinez


2

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:

  • Boost.ASIO không có hỗ trợ chính thức cho iOS và Android, ví dụ: hệ thống xây dựng của nó không hoạt động cho iOS.
  • libuv xây dựng dễ dàng cho iOS và Android, với sự hỗ trợ chính thức cho Android ngay trong tài liệu của họ . Kịch bản xây dựng iOS chung của riêng tôi cho các dự án dựa trên Autotools hoạt động mà không gặp sự cố.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.