Câu trả lời:
Tôi nghĩ rằng điều này trả lời câu hỏi của bạn:
Từ Richard Stevens (rstevens@noao.edu):
Sự khác biệt cơ bản là fd_set của select () là mặt nạ bit và do đó có một số kích thước cố định. Hạt nhân có thể không giới hạn kích thước này khi kernel được biên dịch, cho phép ứng dụng xác định FD_SETSIZE theo bất cứ điều gì nó muốn (như các bình luận trong tiêu đề hệ thống ngụ ý ngày nay) nhưng phải mất nhiều công sức hơn. Nhân của 4.4BSD và chức năng thư viện Solaris đều có giới hạn này. Nhưng tôi thấy rằng BSD / OS 2.1 hiện đã được mã hóa để tránh giới hạn này, vì vậy điều đó là có thể, chỉ là một vấn đề nhỏ về lập trình. :-) Ai đó nên nộp báo cáo lỗi Solaris về điều này và xem nó có được sửa hay không.
Tuy nhiên, với poll (), người dùng phải phân bổ một mảng các cấu trúc pollfd và vượt qua số lượng mục trong mảng này, do đó không có giới hạn cơ bản. Như Casper lưu ý, ít hệ thống có poll () hơn select, do đó, hệ thống này dễ mang theo hơn. Ngoài ra, với các triển khai ban đầu (SVR3), bạn không thể đặt bộ mô tả thành -1 để báo cho kernel bỏ qua một mục trong cấu trúc pollfd, điều này khiến cho việc loại bỏ các mục khỏi mảng trở nên khó khăn; SVR4 có được điều này. Cá nhân, tôi luôn sử dụng select () và hiếm khi thăm dò ý kiến (), vì tôi cũng chuyển mã của mình sang môi trường BSD. Ai đó có thể viết một triển khai thăm dò ý kiến () sử dụng select () cho các môi trường này, nhưng tôi chưa bao giờ thấy một môi trường nào. Cả select () và poll () đang được chuẩn hóa bởi POSIX 1003.1g.
Các email được tham chiếu ở trên ít nhất là năm 2001; các poll()
bao gồm BSD - lệnh bây giờ (2017) được hỗ trợ trên tất cả các hệ điều hành hiện đại. Trong thực tế, một số người tin rằng select()
nên được phản đối . Các ý kiến sang một bên, các vấn đề di động xung quanh poll()
không còn là mối quan tâm trên các hệ thống hiện đại. Hơn nữa, epoll()
kể từ đó đã được phát triển (bạn có thể đọc trang man ) và tiếp tục tăng phổ biến.
Đối với sự phát triển hiện đại, có lẽ bạn không muốn sử dụng select()
, mặc dù không có gì sai rõ ràng với nó. poll()
và đó là sự tiến hóa hiện đại hơn epoll()
, cung cấp các tính năng tương tự (và hơn thế nữa) select()
mà không phải chịu những hạn chế trong đó.
select
hay poll
:(
Cuộc select()
gọi yêu cầu bạn tạo ba bitmas để đánh dấu ổ cắm và mô tả tệp nào bạn muốn xem để đọc, viết và lỗi và sau đó hệ điều hành đánh dấu những hoạt động nào trong thực tế đã có một loại hoạt động nào đó; poll()
bạn có tạo một danh sách ID mô tả và hệ điều hành đánh dấu mỗi ID đó với loại sự kiện đã xảy ra.
Các select()
phương pháp là khá vụng về và kém hiệu quả.
Thông thường có hơn một nghìn mô tả tệp tiềm năng có sẵn cho một quy trình. Nếu một quy trình chạy dài chỉ có một vài mô tả được mở, nhưng ít nhất một trong số chúng đã được gán một số lượng lớn, thì bitmask được truyền vào select()
phải đủ lớn để chứa bộ mô tả cao nhất đó - vì vậy toàn bộ phạm vi hàng trăm bit sẽ không được đặt trước rằng hệ điều hành phải lặp đi lặp lại trên mỗi select()
cuộc gọi chỉ để phát hiện ra rằng chúng không được đặt.
Sau khi select()
trả về, người gọi phải lặp qua cả ba bitmas để xác định sự kiện nào đã diễn ra. Trong rất nhiều ứng dụng điển hình, chỉ có một hoặc hai mô tả tệp sẽ có lưu lượng truy cập mới tại bất kỳ thời điểm nào, nhưng cả ba bitmas phải được đọc từ đầu đến cuối để khám phá những mô tả đó là gì.
Bởi vì hệ điều hành báo hiệu cho bạn về hoạt động bằng cách viết lại bitmasks, chúng bị hủy hoại và không còn được đánh dấu bằng danh sách mô tả tệp bạn muốn nghe. Bạn có thể phải xây dựng lại toàn bộ bitmask từ một số danh sách khác mà bạn giữ trong bộ nhớ hoặc bạn phải giữ một bản sao của mỗi bitmask và memcpy()
khối dữ liệu trên đầu các bitmas bị hủy hoại sau mỗi select()
cuộc gọi.
Vì vậy, poll()
cách tiếp cận hoạt động tốt hơn nhiều vì bạn có thể tiếp tục sử dụng lại cấu trúc dữ liệu tương tự.
Trên thực tế, poll()
đã truyền cảm hứng cho một cơ chế khác trong các nhân Linux hiện đại: epoll()
cải thiện hơn nữa cơ chế này để cho phép một bước nhảy vọt khác về khả năng mở rộng, vì các máy chủ ngày nay thường muốn xử lý hàng chục ngàn kết nối cùng một lúc. Đây là một giới thiệu tốt cho nỗ lực:
http://scotdoyle.com/python-epoll-howto.html
Mặc dù liên kết này có một số biểu đồ đẹp cho thấy lợi ích của epoll()
(bạn sẽ lưu ý rằng select()
đến thời điểm này được coi là không hiệu quả và lỗi thời đến nỗi nó thậm chí không có được một dòng trên các biểu đồ này!):
http://lse.sourceforge.net/epoll/index.html
Cập nhật: Đây là một câu hỏi khác về Stack Overflow, câu trả lời của nó thậm chí còn chi tiết hơn về sự khác biệt:
Hãy cẩn thận với các lò phản ứng chọn / thăm dò so với epoll trong Twisted
Cả hai đều chậm và chủ yếu giống nhau , nhưng khác nhau về kích thước và một số loại tính năng!
Khi bạn viết một trình vòng lặp, Bạn cần sao chép bộ select
mỗi lần! Trong khi poll
đã sửa loại vấn đề này để có mã đẹp. Một sự khác biệt khác là poll
có thể xử lý hơn 1024 mô tả tệp (FD) theo mặc định. poll
có thể xử lý các sự kiện khác nhau để làm cho chương trình dễ đọc hơn thay vì có nhiều biến để xử lý loại công việc này. Hoạt động trong poll
và select
là tuyến tính và chậm vì có nhiều kiểm tra.