2010-05-04 32 views
10

Tôi có thể hiểu lý do tại sao các ứng dụng mạng sẽ sử dụng ghép kênh (để không tạo quá nhiều luồng) và tại sao chương trình sẽ sử dụng các cuộc gọi không đồng bộ cho pipelining (hiệu quả hơn). Nhưng tôi không hiểu mục đích hiệu quả của AsynchronousFileChannel.Tại sao lại sử dụng AsynchronousFileChannel của Java?

Bất kỳ ý tưởng nào?

Trả lời

7

Đó là kênh mà bạn có thể sử dụng để đọc tệp không đồng bộ, tức là các thao tác I/O được thực hiện trên một chuỗi riêng biệt, sao cho chuỗi bạn gọi từ đó có thể thực hiện những việc khác trong khi các hoạt động I/O xảy ra.

Ví dụ: Phương thức read() của lớp trả về đối tượng Future để nhận kết quả đọc dữ liệu từ tệp. Vì vậy, những gì bạn có thể làm là gọi read(), sẽ trả về ngay lập tức với đối tượng Future. Trong nền, một luồng khác sẽ đọc dữ liệu thực tế từ tệp. Chuỗi của riêng bạn có thể tiếp tục làm mọi thứ và khi cần dữ liệu đọc, bạn gọi get() trên đối tượng Future. Điều đó sau đó sẽ trả về dữ liệu (nếu chủ đề nền chưa hoàn thành việc đọc dữ liệu, nó sẽ làm cho khối chuỗi của bạn cho đến khi dữ liệu sẵn sàng). Ưu điểm của điều này là thread của bạn không phải đợi toàn bộ chiều dài của hoạt động đọc; nó có thể làm một số thứ khác cho đến khi nó thực sự cần dữ liệu.

Xem the documentation.

Lưu ý rằng AsynchronousFileChannel sẽ là một lớp mới trong Java SE 7 chưa được phát hành.

+0

Cảm ơn, nhưng tôi đã tự hỏi thêm về những lý do hiệu quả - Tôi không thể hiểu tại sao thực hiện I/O trong một chủ đề khác giúp. Một luồng luôn phải chặn cho I/O và không có tài nguyên được báo cáo lại, sử dụng tính năng phần cứng hoặc bất kỳ hành vi nâng cao hiệu suất nào khác. –

+9

Lợi thế của việc này là bạn * không * cần hai chủ đề. Nếu bạn đang viết một blob lớn dữ liệu, ở mức thấp, bộ điều khiển đĩa thực hiện công việc ghi dữ liệu vào đĩa trước khi báo hiệu một ngắt làm tăng stack để gọi trình xử lý hoàn thành của bạn. Chủ đề của bạn không cần chặn trong quá trình này và có thể thực hiện các nội dung khác. Bạn sử dụng một chuỗi ít hơn, trình quản lý chuỗi chỉ quản lý một chuỗi ít hơn, bạn không cần sử dụng thông báo java. Về cơ bản, bạn sử dụng ít tài nguyên hơn để làm điều tương tự. – lenkite

+2

Hệ điều hành cũng có thể tối ưu hóa thứ tự các hoạt động IO không đồng bộ được thực hiện. Ví dụ: nếu bạn có nhiều lần đọc của nhiều vùng trong tệp được thực hiện không đồng bộ, hệ điều hành có thể nhóm chúng lại với nhau thành lần đọc tuần tự mà không phải lo lắng về việc thực hiện tất cả các thao tác theo thứ tự chính xác. –

3

Tôi vừa mới gặp một lý do khác, không ngờ đến khi sử dụng AsynchronousFileChannel. Khi thực hiện ghi theo định hướng ngẫu nhiên trên các tệp lớn (vượt quá bộ nhớ vật lý để bộ nhớ đệm không hỗ trợ mọi thứ) trên NTFS, tôi thấy rằng AsynchronousFileChannel thực hiện gấp đôi hoạt động, trong chế độ một luồng, so với một FileChannel bình thường. Dự đoán tốt nhất của tôi là vì io không đồng bộ sôi xuống IO chồng lên nhau trong Windows 7, trình điều khiển hệ thống tệp NTFS có thể cập nhật cấu trúc nội bộ của chính nó nhanh hơn khi không phải tạo điểm đồng bộ sau mỗi cuộc gọi .

tôi vi benchmarked chống RandomAccessFile để xem làm thế nào nó sẽ thực hiện (kết quả rất gần với FileChannel, và vẫn còn một nửa số hiệu suất của AsynchronousFileChannel.

Không chắc điều gì xảy ra với đa luồng viết. Đây là trên Java 7, trên một SSD (SSD là một đơn đặt hàng của cường độ nhanh hơn từ tính, và một thứ tự cường độ nhanh hơn trên các tập tin nhỏ hơn phù hợp với bộ nhớ)

Sẽ rất thú vị để xem nếu tỷ lệ tương tự giữ trên Linux.

+0

Thật vậy, miễn là tệp của bạn ngắn để phù hợp với bộ nhớ cache của hệ điều hành, I/O hoàn tất ngay lập tức bất kể I/O của bạn là đồng bộ hay không. Tôi chỉ cần thêm rằng bạn sẽ nhận được tối đa 2x tốc độ khi I/O của bạn và tính toán có chiều dài tương đương. Nếu tính toán chỉ là một phần nhỏ của thời gian I/O hoặc I/O là ngắn hơn đáng kể so với tính toán thì chồng chéo chúng cũng không có ý nghĩa. – Val

3

Lý do chính tôi có thể nghĩ đến việc sử dụng IO không đồng bộ là tốt hơn sử dụng bộ xử lý. Hãy tưởng tượng bạn có một số ứng dụng thực hiện một số loại xử lý trên một tệp. Và cũng giả sử bạn có thể xử lý dữ liệu chứa trong tập tin theo khối. Nếu bạn không sử dụng IO không đồng bộ thì ứng dụng của bạn có thể sẽ hoạt động như sau:

  1. Đọc khối dữ liệu. Không sử dụng bộ xử lý tại thời điểm này vì bạn đang bị chặn chờ dữ liệu được đọc.
  2. xử lý dữ liệu bạn vừa đọc. Tại thời điểm này, ứng dụng của bạn sẽ bắt đầu tiêu thụ các chu kỳ CPU khi nó xử lý dữ liệu.
  3. Nếu có thêm dữ liệu để đọc, hãy bấm # 1.

Việc sử dụng bộ xử lý sẽ tăng lên rồi đến 0 và sau đó lên và sau đó đến 0, .... Lý tưởng nhất là bạn không muốn nhàn rỗi nếu bạn muốn ứng dụng của mình hiệu quả và xử lý dữ liệu nhanh nhất có thể. Một cách tiếp cận tốt hơn sẽ là:

  1. Issue async đọc
  2. Khi đọc xong vấn đề tiếp theo async đọc và sau đó xử lý dữ liệu

Bước đầu tiên là bootstrapping. Bạn chưa có dữ liệu để bạn phải đọc. Từ đó trở đi, khi bạn nhận được thông báo, đọc đã hoàn tất, bạn phát hành một async khác đọc và sau đó xử lý dữ liệu. Lợi ích ở đây là khi bạn xử lý xong đoạn dữ liệu, lần đọc tiếp theo có thể đã hoàn tất, vì vậy bạn luôn có sẵn dữ liệu để xử lý và do đó bạn sử dụng bộ vi xử lý hiệu quả hơn. Nếu quá trình xử lý của bạn kết thúc trước khi đọc xong, bạn có thể cần phát hành nhiều lần đọc không đồng bộ để bạn có nhiều dữ liệu hơn để xử lý.

Nick

0

Đây là điều mà không ai có đề cập: FileChannel, vì nó thực hiện InterruptibleChannel, cũng như bất cứ điều gì mà sử dụng nó như OutputStream trả về bởi Files.newOutputStream(), có hạnh [1] [2] bất động sản rằng bất kỳ hoạt động chặn nào mà nó thực hiện (ví dụ: read()write()) từ một chuỗi trong số interrupted state sẽ tự làm cho chính bản thân Channel đóng lại với java.nio.channels.ClosedByInterruptException.

Đối với những nơi mà đây là vấn đề, sử dụng AsynchronousFileChannel thay vào đó là một cách có thể để xây dựng một giải pháp.

Các vấn đề liên quan