Các trường hợp sử dụng cho bộ lập lịch RxJava


253

Trong RxJava có 5 lịch trình khác nhau để lựa chọn:

  1. ngay lập tức () : Tạo và trả về Bộ lập lịch thực thi công việc ngay lập tức trên luồng hiện tại.

  2. trampoline () : Tạo và trả về Trình lập lịch biểu mà hàng đợi hoạt động trên luồng hiện tại sẽ được thực thi sau khi công việc hiện tại hoàn thành.

  3. newThread () : Tạo và trả về Trình lập lịch biểu tạo Chủ đề mới cho mỗi đơn vị công việc.

  4. tính toán () : Tạo và trả về một Trình lập lịch biểu dành cho công việc tính toán. Điều này có thể được sử dụng cho các vòng lặp sự kiện, xử lý các cuộc gọi lại và công việc tính toán khác. Không thực hiện công việc ràng buộc IO trên lịch trình này. Sử dụng lịch trình. io () thay vào đó.

  5. io () : Tạo và trả về Bộ lập lịch dành cho công việc ràng buộc IO. Việc thực hiện được hỗ trợ bởi nhóm luồng Executor sẽ phát triển khi cần thiết. Điều này có thể được sử dụng để thực hiện chặn không đồng bộ IO. Không thực hiện công việc tính toán trên lịch trình này. Sử dụng lịch trình. tính toán () thay vào đó.

Câu hỏi:

3 lịch trình đầu tiên là khá tự giải thích; tuy nhiên, tôi hơi bối rối về tính toánio .

  1. Chính xác thì "Công việc ràng buộc IO" là gì? Được sử dụng để xử lý các luồng ( java.io) và tệp ( java.nio.files)? Nó được sử dụng cho các truy vấn cơ sở dữ liệu? Nó được sử dụng để tải xuống các tệp hoặc truy cập API REST?
  2. Làm thế nào là tính toán () khác nhau từ newthread () ? Có phải tất cả các cuộc gọi tính toán () đều nằm trên một luồng (nền) thay vì một luồng (nền) mới mỗi lần?
  3. Tại sao gọi tính toán () khi thực hiện IO lại không tốt?
  4. Tại sao lại gọi io () khi làm công việc tính toán?

Câu trả lời:


332

Những câu hỏi tuyệt vời, tôi nghĩ rằng tài liệu có thể làm với một số chi tiết hơn.

  1. io()được hỗ trợ bởi nhóm luồng không giới hạn và là loại thứ bạn sử dụng cho các tác vụ không tính toán chuyên sâu, đó là thứ không gây tải nhiều cho CPU. Vì vậy, tương tác với hệ thống tệp, tương tác với cơ sở dữ liệu hoặc dịch vụ trên một máy chủ khác là những ví dụ tốt.
  2. computation()được hỗ trợ bởi một nhóm luồng có giới hạn với kích thước bằng số lượng bộ xử lý có sẵn. Nếu bạn đã cố gắng lên lịch cho công việc chuyên sâu của CPU song song nhiều hơn các bộ xử lý có sẵn (giả sử sử dụng newThread()) thì bạn sẽ sẵn sàng cho việc tạo luồng và chi phí chuyển đổi ngữ cảnh khi các luồng xử lý cho bộ xử lý và nó có khả năng đạt hiệu suất lớn.
  3. Tốt nhất chỉ nên để computation()CPU làm việc chuyên sâu nếu không bạn sẽ không sử dụng CPU tốt.
  4. Thật tệ khi gọi io()công việc tính toán vì lý do được thảo luận trong 2. io()không bị ràng buộc và nếu bạn lên lịch cho hàng ngàn nhiệm vụ tính toán io()song song thì mỗi nghìn nhiệm vụ đó sẽ có một luồng riêng và cạnh tranh cho CPU phát sinh chi phí chuyển đổi ngữ cảnh.

5
Thông qua việc làm quen với nguồn RxJava. Đó là một nguồn gây nhầm lẫn cho tôi trong một thời gian dài và tôi nghĩ rằng các tài liệu cần tăng cường về vấn đề này.
Dave Moten 8/07/2015

2
@IgorGanapolsky Tôi đoán đó là điều bạn hiếm khi muốn làm. Tạo một luồng mới cho mọi đơn vị công việc hiếm khi có lợi cho hiệu quả do các luồng rất tốn kém để xây dựng và phá bỏ. Bạn thường muốn sử dụng lại các luồng mà tính toán () và các trình lập lịch khác làm. Lần duy nhất newThread () có thể có sử dụng hợp pháp (ít nhất là tôi có thể nghĩ đến) là khởi động các nhiệm vụ dài hạn, không thường xuyên, bị cô lập. Thậm chí sau đó tôi có thể sử dụng io () cho kịch bản đó.
tmn

4
Bạn có thể chỉ ra một ví dụ về việc trampoline () sẽ hữu ích không? Tôi hiểu khái niệm này nhưng tôi không thể tìm ra một kịch bản tôi sẽ sử dụng nó trong thực tế. Đó là lịch trình duy nhất mà id vẫn còn là một bí ẩn đối với tôi
tmn

32
Đối với các cuộc gọi mạng, hãy sử dụng Routulers.io () và nếu bạn cần giới hạn số lượng cuộc gọi mạng đồng thời, hãy sử dụng Trình lập lịch biểu.from (Executors.newFixedThreadPool (n)).
Dave Moten

4
Bạn có thể nghĩ rằng đặt timeoutmặc định vào computation()bạn sẽ chặn một chuỗi nhưng không phải vậy. Dưới vỏ bọc computation()sử dụng một ScheduledExecutorServicethời gian trì hoãn hành động không chặn. Vì thực tế computation()này là một ý tưởng tốt bởi vì nếu nó nằm trên một luồng khác thì chúng ta sẽ phải chịu chi phí chuyển đổi luồng.
Dave Moten

3

Điểm quan trọng nhất là cả Lập kế hoạch.ioLập kế hoạch. Tính toán được hỗ trợ bởi các nhóm luồng không bị ràng buộc, trái ngược với các nhóm khác được đề cập trong câu hỏi. Đặc tính này chỉ được chia sẻ bởi Routulers.from ( Executor) trong trường hợp Executor được tạo bằng newCachedThreadPool (không bị ràng buộc với nhóm luồng tự động lấy lại).

Như đã được giải thích rất nhiều trong các phản hồi trước đây và nhiều bài viết trên web, lên lịch , lập kế hoạch và lập kế hoạch sẽ được sử dụng cẩn thận vì chúng được tối ưu hóa cho loại công việc trong tên của chúng. Nhưng, theo quan điểm của tôi, vai trò quan trọng nhất của họ là cung cấp sự đồng thời thực sự cho các luồng phản ứng .

Trái với niềm tin của người mới, các luồng phản ứng không phải là đồng thời mà vốn không đồng bộ và tuần tự. Vì lý do này, Routulers.io chỉ được sử dụng khi thao tác I / O bị chặn (ví dụ: sử dụng lệnh chặn như Apache IOUtils FileUtils.readFileAsString (...) ) do đó sẽ đóng băng chuỗi cuộc gọi cho đến khi hoạt động được làm xong.

Sử dụng một phương thức không đồng bộ, chẳng hạn như Java AsynyncousFileChannel (...) sẽ không chặn luồng gọi trong quá trình hoạt động nên không có điểm nào trong việc sử dụng một luồng riêng biệt. Trên thực tế, các luồng của Routulers.io không thực sự phù hợp với các hoạt động không đồng bộ vì chúng không chạy vòng lặp sự kiện và cuộc gọi lại sẽ không bao giờ ... được gọi.

Logic tương tự áp dụng cho truy cập cơ sở dữ liệu hoặc các cuộc gọi API từ xa. Không sử dụng Trình lập lịch.io nếu bạn có thể sử dụng API không đồng bộ hoặc phản ứng để thực hiện cuộc gọi.

Quay lại đồng thời. Bạn có thể không có quyền truy cập vào API không đồng bộ hoặc API phản ứng để thực hiện các hoạt động I / O không đồng bộ hoặc đồng thời, do đó, cách thay thế duy nhất của bạn là gửi nhiều cuộc gọi trên một luồng riêng biệt. Than ôi, con suối phản ứng là tuần tự ở hai đầu của họ nhưng những tin tức tốt lành là các flatMap () điều hành có thể giới thiệu đồng thời ở cốt lõi của họ .

Đồng thời phải được xây dựng trong cấu trúc luồng, thường sử dụng toán tử FlatMap () . Toán tử mạnh mẽ này có thể được cấu hình để cung cấp nội bộ bối cảnh đa luồng cho Hàm nhúng bản đồ phẳng () của bạn <T, R>. Bối cảnh đó được cung cấp bởi Trình lập lịch đa luồng, chẳng hạn như Trình lập lịch biểu.io hoặc Trình lập lịch biểu .

Tìm thêm chi tiết trong các bài viết về Bộ lập lịchĐồng thời RxJava2 , nơi bạn sẽ tìm thấy mẫu mã và giải thích chi tiết về cách sử dụng Bộ lập lịch liên tục và đồng thời.

Hi vọng điêu nay co ich,

Softjake


2

Bài đăng blog này cung cấp một câu trả lời tuyệt vời

Từ bài viết trên blog:

Routulers.io () được hỗ trợ bởi nhóm luồng không giới hạn. Nó được sử dụng cho công việc loại I / O không cần CPU, bao gồm tương tác với hệ thống tệp, thực hiện các cuộc gọi mạng, tương tác cơ sở dữ liệu, v.v. Nhóm luồng này được sử dụng để thực hiện chặn IO không đồng bộ.

Routulers.computing () được hỗ trợ bởi nhóm luồng giới hạn với kích thước lên đến số lượng bộ xử lý có sẵn. Nó được sử dụng cho các công việc tính toán hoặc sử dụng nhiều CPU như thay đổi kích thước hình ảnh, xử lý các tập dữ liệu lớn, v.v. Hãy cẩn thận: khi bạn phân bổ nhiều luồng tính toán hơn các lõi có sẵn, hiệu suất sẽ giảm do chuyển đổi ngữ cảnh và phí tạo luồng thời gian của bộ xử lý.

Lên lịch.newThread () tạo một luồng mới cho mỗi đơn vị công việc được lên lịch. Bộ lập lịch này rất tốn kém vì luồng mới được sinh ra mỗi lần và không có việc sử dụng lại xảy ra.

Routulers.from (Executor execor) tạo và trả về một lịch trình tùy chỉnh được hỗ trợ bởi bộ thực thi được chỉ định. Để giới hạn số lượng luồng đồng thời trong nhóm luồng, hãy sử dụng Trình lập lịch biểu.from (Executors.newFixedThreadPool (n)). Điều này đảm bảo rằng nếu một tác vụ được lên lịch khi tất cả các luồng được chiếm, nó sẽ được xếp hàng. Các chủ đề trong nhóm sẽ tồn tại cho đến khi nó được tắt một cách rõ ràng.

Chủ đề chính hoặc AndroidSchedulers.mainThread () được cung cấp bởi thư viện tiện ích mở rộng RxAndroid cho RxJava. Chủ đề chính (còn được gọi là chủ đề UI) là nơi xảy ra tương tác người dùng. Cần chú ý không làm quá tải luồng này để ngăn chặn giao diện người dùng không phản hồi nhanh hoặc tệ hơn là hộp thoại Ứng dụng không phản hồi (ANR).

Routulers.single () là tính năng mới trong RxJava 2. Bộ lập lịch này được hỗ trợ bởi một luồng thực thi các tác vụ theo tuần tự theo thứ tự được yêu cầu.

Bộ lập lịch.trampoline () thực thi các tác vụ theo cách thức FIFO (First In, First Out) bởi một trong các luồng công nhân tham gia. Nó thường được sử dụng khi thực hiện đệ quy để tránh phát triển ngăn xếp cuộc gọi.

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.