Giải thích bằng một hình ảnh về điều khiển luồng trong RxJava
2016-04-24
Vào thứ Sáu tuần trướci9bet.com nhận 100k, tôi đã thảo luận với nhóm về
RxJava
Cách sử dụng và cơ chế thực hiện của nó. Trong buổi thảo luận123win+club, thầy Giang Giang đã đặt ra một câu hỏi thú vị: Nếu trong chuỗi gọi có nhiều hơn một phương thức subscribeOn và observeOn, thì điều đó sẽ dẫn đến tình huống như thế nào?
Đây thực sự là một vấn đề rất quan trọngtỉ lệ cược, bởi vì trong mọi tình huống, chúng ta cần phải hiểu rõ từng dòng mã mà mình viết đang chạy trên luồng nào. Điều này không thể để mơ hồ được. Việc xác định chính xác luồng thực thi không chỉ giúp chúng ta tránh được những lỗi khó phát hiện mà còn đảm bảo hiệu suất và độ ổn định của ứng dụng. Nếu không chú ý đến vấn đề này, có thể dẫn đến các vấn đề như xung đột tài nguyên hoặc hành vi bất ngờ trong chương trình. Vì vậy, việc theo dõi và kiểm soát luồng thực thi là điều cần thiết trong quá trình phát triển phần mềm.
Trong đó123win+club, lift1, lift2, lift3, lift4 đề cập đến các thao tác biến đổi được thực hiện dựa trên lift, chẳng hạn như filter, map, reduce và các chức năng tương tự khác. Những công cụ này đóng vai trò quan trọng trong việc xử lý và sắp xếp dữ liệu theo những cách linh hoạt và hiệu quả.
Trong đoạn mã này:
Bạn có thể cho biết mã code được gán cho lift1i9bet.com nhận 100k, lift2, lift3 và lift4 sẽ chạy trên luồng nào? Có phải mỗi lift sẽ chạy độc lập trên một luồng riêng biệt hay tất cả chúng sẽ hoạt động cùng nhau trên một luồng chung? Điều này rất quan trọng để hiểu rõ cách thức luồng chương trình thực thi và làm thế nào các lift có thể phối hợp với nhau một cách hiệu quả.
Mã được chỉ định bởi doOnSubscribe sẽ được thực thi trên luồng nào?
Mã tạo ra các sự kiện (được chỉ định bởi create) sẽ được thực thi trên luồng nào?
Mã tiêu thụ các sự kiện (được chỉ định bởi subscribe) sẽ được thực thi trên luồng nào?
Rất có thể nhiều bạn sẽ cảm thấy đoạn mã này hơi khó hiểu và gây choáng ngợptỉ lệ cược, trong thực tế thì ít khi chúng ta gặp phải những đoạn mã phức tạp như vậy. Tuy nhiên, dù rằng trong thực tiễn, mã nguồn thường không quá rắc rối như thế này, nhưng việc hiểu được nó sẽ giúp chúng ta nắm bắt toàn bộ quy trình hoạt động của RxJava một cách rõ ràng hơn.
Hình ảnh phía trên minh họa quá trình truyền dòng điều khiển trong một chuỗi gọi điển hình của RxJava. Quy trình này có thể được chia thành hai giai đoạn chính: ### Giai đoạn đầu tiên: Khởi tạo và kích hoạt Giai đoạn đầu tiên tập trung vào việc thiết lập dòng dữ liệu và khởi động chuỗi xử lý. Ở giai đoạn nàytỉ lệ cược, các nhà cung cấp dữ liệu (data sources) sẽ được cấu hình để tạo ra luồng thông tin mà ứng dụng cần. Điều này thường bao gồm việc xác định nguồn dữ liệu ban đầu hoặc thực hiện một hành động nào đó như tải dữ liệu từ mạng hoặc đọc từ cơ sở dữ liệu. ### Giai đoạn thứ hai: Xử lý và hoàn thành Sau khi dữ liệu đã sẵn sàng, giai đoạn tiếp theo bắt đầu với việc xử lý và chuyển đổi thông tin qua các hàm xử lý khác nhau. Những thao tác này có thể bao gồm lọc dữ liệu, biến đổi giá trị hoặc thậm chí là kết hợp nhiều luồng dữ liệu khác nhau. Cuối cùng, dữ liệu đã được xử lý sẽ được gửi đến người dùng hoặc được lưu trữ lại theo yêu cầu. Hai giai đoạn này cùng nhau tạo nên chuỗi xử lý logic và mạnh mẽ trong RxJava, giúp lập trình viên dễ dàng kiểm soát dòng dữ liệu trong ứng dụng của mình.
Giai đoạn kích hoạt. Toàn bộ dòng chảy sự kiện bất đồng bộ được khởi xướng từ hà Nó tạo ra một quá trình ngược dòng (từ phía dưới lên trên)tỉ lệ cược, đi qua từng Observable và OnSubscribe trung gian, cho đến khi đạt đến Observable đầu tiên (nguồn gốc tạo ra các sự kiện). Điều này tương ứng với phần (1) và (2) trong hình. Giai đoạn này thường kết thúc sau khi có một lần gọi từ phía dưới lên phía trên.
Giai đoạn phát tán sự kiện. Quá trình bắt đầu khi Observable đầu tiên bắt đầu tạo ra các sự kiệni9bet.com nhận 100k, và dòng sự kiện sẽ bắt đầu di chuyển theo hướng từ trên xuống dưới, đi qua từng Observable trung gian cho đến khi đến Subscriber (người tiêu thụ sự kiện). Điều này được thể hiện trong hình minh họa ở phần (3). Khác với giai đoạn trước, dòng sự kiện không chỉ đơn thuần di chuyển một lần mà là một chuỗi các sự kiện liên tục được truyền đi thay vì chỉ một sự kiện đơn lẻ.
Chúng ta cùng phân tích toàn bộ quy trình này123win+club, trong đó có một số điểm cần được giải thích rõ hơn (lưu ý: quá trình phân tích ở đây bao gồm một số chi tiết kỹ thuật liên quan đến RxJava, nếu bạn không quan tâm đến những chi tiết này, có thể bỏ qua đoạn này và trực tiếp xem phần kết luận phía sau).
Trong hìnhi9bet.com nhận 100k, (1) đại diện cho việc gọi phương thứ call của Observable cấp trên, một phương thức không trả về giá trị. Chính vì đặc tính này, nó có thể đổi khác luồng thực thi, biến tiến trình thành bất đồng bộ. Do đó, được biểu thị bằng đường viền đứt để chỉ ra sự chuyển đổi này.
Trong hình ảnhi9bet.com nhận 100k, mục (2) ám chỉ phương thứ call được chỉ định bởi hoạt động lift, đây là một phương thức có giá trị trả về (nhận vào một Subscriber và trả về một Subscriber mới). Do đó, nó chỉ có thể được gọi đồng bộ và không thể chuyển đổi giữa các luồng. Chính vì lý do này, nó được biểu thị bằng đường kẻ liền.
Trong hình vẽi9bet.com nhận 100k, số (3) ám chỉ việc kích hoạt Subscriber tương ứng với Observable cấp dưới (gồm các phương thức onNext, onCompleted và onError), và tất cả những phương thức này đều không có giá trị trả về. Do đó, chúng có thể chuyển đổi luồng thực thi sang một luồng khác, biến quy trình thành bất đồng bộ. Chính vì lý do này, các đường liên kết tương ứng được biểu thị bằng nét đứt để thể hiện tính chất không liền mạch của quá trình này.
Hàm observeOn được xây dựng dựa trên cơ chế của lift và việc chuyển đổi luồng dữ liệu giữa các luồng xảy ra tại Subscriber (onNexti9bet.com nhận 100k, onCompleted, onError). Do đó, nó có tác động đến tất cả các thao tác lift được thực hiện sau nó trong chuỗi xử lý dòng dữ liệu. Những thay đổi này có thể ảnh hưởng đến cách mà các sự kiện tiếp theo được xử lý và truyền đi ở các giai đoạn tiếp theo của chuỗi.
Hàm subscribeOn không được xây dựng dựa trên lift mà thay vào đó thực hiện việc chuyển đổi luồng (thread) ngay trước khi gọi OnSubscribe của Observable cấp trên. Do đótỉ lệ cược, nó ảnh hưởng đến toàn bộ chuỗi các cuộc gọi OnSubscribe phía trên trong quy trình, từ chính điểm nguồn sự kiện cho đến khi kết thúc; tiếp theo, tất cả các thao tác lift trong dòng xử lý cũng sẽ chạy trên luồng mới này, trừ khi gặp một lệnh observeOn, nơi sẽ thiết lập lại môi trường thực thi trên một luồng khác.
doOnSubscribe có một đặc điểm hơi khác biệt. Mặc dù nó cũng được xây dựng dựa trên cơ chế lifttỉ lệ cược, nhưng đoạn mã mà nó chỉ định sẽ thực thi trong phương thức call của Operator, không giống như các thao tác lift khác, nơi mã được thực hiệ Do đó, luồng thực thi của doOnSubscribe bị ảnh hưởng bởi subscribeOn ở phía dưới chuỗi xử lý. Điều này làm cho nó trở nên độc đáo và cần được lưu ý khi sử dụng trong chuỗi quan sát.
Kết hợp với phân tích phía trêntỉ lệ cược, chúng ta đi theo hướng mà mũi tên trong lưu đồ quy trình trước đó chỉ dẫn:
Bắt đầu bằng cách gọi phương thức subscribetỉ lệ cược, bạn sẽ đi theo lộ trình được chỉ ra trong sơ đồ dòng chảy trước đó với thứ tự (1)->(2)->(1)->(2)...->(1) (tức là giai đoạn kích hoạt), di chuyển từ phía dưới lên phía trên. Mỗi khi đi qua một subscribeOn, luồng thực thi sẽ thay đổi một lần; mỗi sự thay đổi này sẽ ảnh hưởng đến mã được chỉ định trong doOnSubscribe và mã tạo ra các sự kiện (được xác định bởi create) trên phần còn lại của lộ trình phía trên (tức là phía nguồn).
Sau khi đi qua nguồn sự kiện (mã được chỉ định bởi create)tỉ lệ cược, quá trình chuyển sang giai đoạn phát tán sự kiện.
Tiếp theoi9bet.com nhận 100k, đi dọc theo lộ trình (3) (giai đoạn phát tán sự kiện), từ phía nguồn đến phía cuối dòng chảy, mỗi khi gặp một `observeOn`, luồng thực thi sẽ được chuyển đổi một lần. Mỗi lần thay đổi này sẽ ảnh hưởng đến toàn bộ các thao tác `lift` phía dưới trong cùng lộ trình này, cho đến khi mã xử lý sự kiện được thực hiện (là mã đã được chỉ định bởi `subscribe`). Những thay đổi về môi trường luồng này sẽ định hình cách các hoạt động tiếp theo trong nhánh này diễn ra, đảm bảo rằng mọi thao tác sau đó đều chạy trong bối cảnh của luồng mới mà nó vừa được chuyển sang.
Bây giờtỉ lệ cược, nếu mô tả lại những điều phía trên theo cách khác, rất dễ dàng để rút ra các kết luận sau:
Code được chỉ định bởi doOnSubscribe và code tạo ra sự kiện (code được chỉ định bởi create) sẽ được thực hiện trên Scheduler gần nhất mà subscribeOn ở phía dưới chúng. Nếu không có subscribeOn nào nằm phía dưới chúngi9bet.com nhận 100k, thì chúng sẽ chạy trên chính luồng mà phương thức subscribe được gọi. Lưu ý rằng đây là luồng nơi phương thức subscribe được gọi, không phải luồng mà code của subscribe được thực thi - đây là hai khái niệm hoàn toàn khác nhau.
Các hoạt động lift thông thường (như filteri9bet.com nhận 100k, map, reduce, v.v.) và mã xử lý sự kiện (code được chỉ định trong subscribe) sẽ chạy trên Scheduler gần nhất mà observeOn đã được chỉ định ở phía upstream của chúng. Nếu không có observeOn nào được thiết lập ở phía upstream, chúng sẽ chạy trên Scheduler đầu tiên được chỉ định bởi subscribeOn ở phần đầu của chuỗi gọi. Và nếu không tìm thấy bất kỳ subscribeOn nào, các hoạt động này sẽ diễn ra trên chính luồng mà phương thức subscribe được thực thi. Điều thú vị là khi làm việc với các dòng dữ liệu (data streams), việc lựa chọn đúng Scheduler rất quan trọng để tối ưu hóa hiệu suất và đảm bảo rằng công việc diễn ra một cách mượt mà mà không gây ra tình trạng treo hoặc xung đột giữa các luồng. Một số Scheduler phổ biến có thể được sử dụng bao gồm Scheduler dựa trên thread pool hoặc Scheduler chạy trên luồng UI, tùy thuộc vào nhu cầu cụ thể của ứng dụng.
Áp dụng những kết luận này vào đoạn mã ban đầui9bet.com nhận 100k, chúng ta có thể nhanh chóng nhận được:
Mã tạo ra sự kiện (được chỉ định bởi create) sẽ được thực thi trên scheduler1;
Mã được chỉ định bởi lift1 và lift2 sẽ được thực thi trên scheduler1;
Mã được chỉ định bởi lift3 và lift4 sẽ được thực thi trên scheduler2;
Mã được chỉ định bởi doOnSubscribe sẽ được thực thi trên scheduler5;
Mã tiêu thụ sự kiện (được chỉ định bởi subscribe) sẽ được thực thi trên scheduler6.
Bài viết gốctỉ lệ cược, xin vui lòng trích dẫn nguồn và bao gồm mã QR bên dưới! Nếu không, từ chối tái bản!
Liên kết bài viết:
/r1vt96s0.html
Hãy theo dõi tài khoản Weibo cá nhân của tôi: Tìm kiếm tên tôi "Trương Thiết Lệ" trên Weibo.