Trạng thái của I / O không đồng bộ POSIX (AIO) là gì?


93

Có nhiều trang nằm rải rác trên web mô tả các cơ sở của POSIX AIO với số lượng chi tiết khác nhau. Không ai trong số họ là khủng khiếp gần đây. Không rõ họ đang mô tả chính xác những gì. Ví dụ: trang web "chính thức" (?) Cho hỗ trợ I / O không đồng bộ của nhân Linux ở đây cho biết rằng các ổ cắm không hoạt động, nhưng các trang hướng dẫn "aio.h" trên máy trạm Ubuntu 8.04.1 của tôi dường như ngụ ý rằng nó hoạt động cho các trình mô tả tệp tùy ý. Sau đó, có một dự án khác dường như hoạt động ở lớp thư viện với ít tài liệu hơn.

Tôi muốn biết:

  • Mục đích của POSIX AIO là gì? Cho rằng ví dụ rõ ràng nhất về cách triển khai mà tôi có thể tìm thấy nói rằng nó không hỗ trợ các ổ cắm, toàn bộ điều này có vẻ kỳ lạ đối với tôi. Nó chỉ dành cho I / O đĩa không đồng bộ? Nếu vậy, tại sao lại là API siêu tổng quát? Nếu không, tại sao đĩa I / O là thứ đầu tiên bị tấn công?
  • Ở đâu có các chương trình POSIX AIO hoàn chỉnh mà tôi có thể xem?
  • Có ai thực sự sử dụng nó, thực sự?
  • Những nền tảng nào hỗ trợ POSIX AIO? Họ hỗ trợ những phần nào của nó? Có ai thực sự ủng hộ "Bất kỳ I / O đến bất kỳ FD nào" <aio.h>có vẻ như hứa hẹn không?

Các cơ chế ghép kênh khác có sẵn cho tôi là hoàn toàn tốt, nhưng những đoạn thông tin ngẫu nhiên trôi nổi xung quanh đó khiến tôi tò mò.

Câu trả lời:


27

I / O mạng không phải là ưu tiên cho AIO vì mọi người viết máy chủ mạng POSIX đều sử dụng phương pháp tiếp cận dựa trên sự kiện, không chặn. Phương pháp tiếp cận "hàng tỷ chuỗi chặn" kiểu cũ của Java rất tệ.

I / O ghi đĩa đã được lưu vào bộ đệm và I / O đọc đĩa có thể được tải trước vào bộ đệm bằng các chức năng như posix_fadvise. Điều đó khiến I / O đĩa trực tiếp, không có bộ đệm là mục đích hữu ích duy nhất cho AIO.

I / O trực tiếp, không có bộ đệm chỉ thực sự hữu ích cho cơ sở dữ liệu giao dịch và những cơ sở dữ liệu đó có xu hướng viết các luồng hoặc quy trình của riêng họ để quản lý I / O đĩa của họ.

Vì vậy, cuối cùng khiến POSIX AIO ở vị trí không phục vụ bất kỳ mục đích hữu ích nào . Đừng sử dụng nó.


8
Còn về việc đọc / ghi từ các hệ thống tệp mạng (NFS, Samba) thì sao?
Alex B

1
tốt. Tôi có một số tác giả ngu ngốc lớn, nếu tôi để chúng vào bộ nhớ cache, sẽ đạt mức dirty_ratio ở mức cao nhất, chặn mọi người khác. Nếu tôi chỉ sử dụng IO trực tiếp trên chúng thì quá chậm. Nếu tôi chỉ có 1 luồng, tôi có thể tự quản lý, nhưng sẽ khó hỗ trợ các ưu tiên IO khác nhau trong 1 luồng. AIO + CFQ wouls thực sự dường như một sự kết hợp tốt, nếu AIO làm việc
n-alexander

37
Tôi không đồng ý. Đĩa I / O có xu hướng được lưu vào bộ đệm nhưng nó có thể bị chặn. Khi thăm dò ý kiến ​​() trong một tệp FD, nó luôn báo cáo rằng FD có thể đọc được, ngay cả khi nó sẽ chặn. Điều này làm cho nó không thể thực hiện các hoạt động không chặn trên các tệp đĩa theo cách xảy ra, trừ khi một người sử dụng luồng hoặc AIO.
Hongli

2
@Matt: Thứ tự không quan trọng đối với ổ cắm datagram. @Zan: I / O không đồng bộ rất tốt để đệm trước dữ liệu phát trực tuyến thời gian thực, ví dụ như trình phát đa phương tiện.
Ben Voigt

13
Không đúng là AIO vô dụng trong các hệ thống dựa trên sự kiện. Bạn thực sự có thể truy cập mạng không sao chép với AIO thích hợp, điều mà bạn không thể thực hiện với thông báo dựa trên sự kiện tới recv (). Những thứ khác có thể khiến điều này chủ yếu là một hạn chế về mặt lý thuyết, nhưng tôi nghĩ rằng việc thiếu AIO thích hợp (được gọi là QUÁ HẤP DẪN trên Windows) là một trong những lỗ hổng lớn cuối cùng trong Linux.
Jon Watte

69

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.


Windows đã hỗ trợ OVERLAPPED I / O tệp đĩa kể từ khi Win32 ra mắt lần đầu. Nó hoàn toàn không mới. Và trên POSIX, không gian tên tín hiệu không phải là quy trình toàn cầu, mà là từng luồng. Các tín hiệu được gửi đến các chủ đề cụ thể (hoặc aio là một ngoại lệ đối với điều đó, không thể nhớ chắc chắn?).
Ben Voigt

1
Không có cách nào để chỉ định luồng AIO truyền tín hiệu của nó đến. Trên linux, dường như chủ yếu phân phối nó đến luồng đã phát hành lệnh aio _ * (), nhưng không phải lúc nào cũng vậy (giải pháp duy nhất mà tôi đã tìm thấy cho việc này là tạo nhiều signalfds). Có một bản vá của linux trong danh sách gửi thư của nhân một vài năm trước sẽ thêm phần này vào, nhưng nó không bao giờ xuất hiện và nó sẽ là một phần mở rộng cho POSIX. Trên Mac OS X, các tín hiệu dường như chủ yếu được chuyển đến luồng chính (theo kinh nghiệm của tôi). Tôi không nghĩ rằng POSIX yêu cầu một hành vi cụ thể, nếu có, tôi rất muốn xem một phần của thông số kỹ thuật.
Arvid

5
Việc triển khai aio_read / write của glibc sử dụng các luồng trong vùng người dùng, vì vậy ngay cả các luồng hạt nhân cũng không được sử dụng ở đây.
Marenz

"Luôn luôn thường" có nghĩa là gì? Các bản ghi được lưu vào bộ đệm bởi hạt nhân cho bất kỳ phương thức nào hoặc khi sử dụng AIO? Có vẻ như phải có một cách để phần mềm chắc chắn rằng việc ghi đã được hoàn thành thành công; nếu không, các mục tiêu về tính toàn vẹn và giao dịch không thể đạt được.
MikeB

Một ví dụ trực tiếp khác mà bạn có thể sử dụng AIO là nginx. Tất cả các chế độ đều được hỗ trợ. Nếu bạn thích giảm tải cho các luồng người dùng, thông thường bạn sẽ thấy nó tệ hơn nhiều so với IO trực tiếp, nhưng AIO gốc của Linux ngang bằng với IO trực tiếp. Tình huống khi AIO có thể mang lại lợi ích đáng kể là áp lực bộ nhớ cache trang nghiêm trọng. Có thể thấy sự khác biệt về khái niệm giữa Async và IO trực tiếp tại đây ftp.dei.uc.pt/pub/linux/kernel/people/suparna/aio-linux.pdf
wick


2

Có aio_write - được thực hiện trong glibc; lần gọi đầu tiên của hàm aio_read hoặc aio_write sinh ra một số chủ đề chế độ người dùng, aio_write hoặc aio_read yêu cầu bài đăng tới chủ đề đó, chuỗi thực hiện pread / pwrite và khi nó kết thúc, câu trả lời được đăng trở lại chuỗi gọi bị chặn.

Ther cũng là aio 'thực' - được hỗ trợ bởi mức hạt nhân (cần libaio cho điều đó, hãy xem lệnh gọi io_submit http://linux.die.net/man/2/io_submit ); cũng cần O_DIRECT cho điều đó (cũng có thể không được hỗ trợ bởi tất cả các hệ thống tệp, nhưng những hệ thống chính hỗ trợ nó)

xem ở đây:

http://lse.sourceforge.net/io/aio.html

http://linux.die.net/man/2/io_submit

Sự khác biệt giữa POSIX AIO và libaio trên Linux?


Nhiều người trong số những thiếu sót của aio_writeđược đề cập ở trên, trong stackoverflow.com/a/5307557/13564
Glyph
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.