Việc làm I / O socket một cách hiệu quả đã được giải quyết với các cổng hoàn thành kqueue, epoll, IO và những thứ tương tự. Thực hiện I / O tệp không đồng bộ là một loại đến muộn (ngoài I / O chồng chéo của windows và hỗ trợ sớm solaris cho posix AIO).
Nếu bạn đang tìm cách thực hiện I / O socket, có lẽ bạn nên sử dụng một trong các cơ chế trên.
Do đó, mục đích chính của AIO là giải quyết vấn đề I / O đĩa không đồng bộ. Đây rất có thể là lý do tại sao Mac OS X chỉ hỗ trợ AIO cho các tệp thông thường chứ không phải ổ cắm (vì dù sao kqueue cũng làm điều đó tốt hơn rất nhiều).
Các hoạt động ghi thường được kernel lưu trong bộ nhớ cache và được xóa sau đó. Ví dụ khi đầu đọc của ổ đĩa tình cờ đi ngang qua vị trí mà khối sẽ được ghi.
Tuy nhiên, đối với các hoạt động đọc, nếu bạn muốn hạt nhân ưu tiên và sắp xếp thứ tự các lần đọc của mình, AIO thực sự là lựa chọn duy nhất. Đây là lý do tại sao kernal có thể (về mặt lý thuyết) làm điều đó tốt hơn bất kỳ ứng dụng cấp người dùng nào:
- Kernel nhìn thấy tất cả I / O đĩa, không chỉ các công việc đĩa ứng dụng của bạn và có thể sắp xếp chúng ở cấp độ chung
- Hạt nhân (có thể) biết vị trí của đầu đọc đĩa và có thể chọn các lệnh đọc mà bạn chuyển cho nó theo thứ tự tối ưu, để di chuyển đầu đọc một khoảng cách ngắn nhất
- Kernel có thể tận dụng lợi thế của hàng đợi lệnh gốc để tối ưu hóa các thao tác đọc của bạn hơn nữa
- Bạn có thể đưa ra nhiều thao tác đọc hơn cho mỗi lệnh gọi hệ thống bằng cách sử dụng lio_listio () so với readv (), đặc biệt nếu các lần đọc của bạn không liền nhau (về mặt logic), tiết kiệm một chút chi phí cuộc gọi hệ thống.
- Chương trình của bạn có thể đơn giản hơn một chút với AIO vì bạn không cần thêm một chuỗi để chặn trong cuộc gọi đọc hoặc ghi.
Điều đó nói rằng, posix AIO có một giao diện khá khó xử, ví dụ:
- Phương tiện gọi lại sự kiện hiệu quả và được hỗ trợ tốt duy nhất là thông qua các tín hiệu, điều này làm cho nó khó sử dụng trong thư viện, vì nó có nghĩa là sử dụng số tín hiệu từ không gian tên tín hiệu toàn cục của quá trình. Nếu hệ điều hành của bạn không hỗ trợ tín hiệu thời gian thực, điều đó cũng có nghĩa là bạn phải lặp lại tất cả các yêu cầu còn tồn đọng của mình để tìm ra yêu cầu nào thực sự hoàn thành (ví dụ: đây là trường hợp của Mac OS X, không phải Linux). Bắt tín hiệu trong môi trường đa luồng cũng gây ra một số hạn chế phức tạp. Bạn thường không thể phản ứng với sự kiện bên trong bộ xử lý tín hiệu, nhưng bạn phải nâng tín hiệu, ghi vào đường ống hoặc sử dụng signalfd () (trên linux).
- lio_suspend () có các vấn đề giống như select (), nó không mở rộng tốt với số lượng công việc.
- lio_listio (), như được triển khai có số lượng công việc khá hạn chế mà bạn có thể vượt qua, và việc tìm giới hạn này theo cách di động không phải là chuyện nhỏ. Bạn phải gọi sysconf (_SC_AIO_LISTIO_MAX), có thể không thành công, trong trường hợp đó bạn có thể sử dụng định nghĩa AIO_LISTIO_MAX, không nhất thiết phải được định nghĩa, nhưng sau đó bạn có thể sử dụng 2, được định nghĩa là đảm bảo được hỗ trợ.
Đối với ứng dụng trong thế giới thực sử dụng posix AIO, bạn có thể xem lighttpd (lighty), cũng đã đăng một phép đo hiệu suất khi giới thiệu hỗ trợ.
Hiện tại, hầu hết các nền tảng posix đều hỗ trợ posix AIO (Linux, BSD, Solaris, AIX, tru64). Windows hỗ trợ nó thông qua I / O tệp chồng chéo của nó. Sự hiểu biết của tôi là chỉ có Solaris, Windows và Linux thực sự hỗ trợ async. tệp I / O tất cả các cách xuống trình điều khiển, trong khi các hệ điều hành khác mô phỏng không đồng bộ. I / O với các luồng nhân. Linux là ngoại lệ, triển khai posix AIO của nó trong glibc mô phỏng các hoạt động không đồng bộ với các luồng cấp người dùng, trong khi giao diện I / O không đồng bộ gốc của nó (io_submit (), v.v.) thực sự không đồng bộ tất cả các cách xuống trình điều khiển, giả sử trình điều khiển hỗ trợ nó .
Tôi tin rằng việc không hỗ trợ posix AIO cho bất kỳ fd nào là khá phổ biến giữa các hệ điều hành, nhưng hạn chế nó ở các tệp thông thường.