SequentialSubscription: các flow theo thread

Cơ sở: apple/servicetalk tại e1704cb (code gốc) và PR 3677 tại 506ce73. Mở từng flow, bấm vào một mũi tên hoặc một thread để xem ghi chú và phạm vi ảnh hưởng. Bốn mục dưới đây cho cùng nội dung ở dạng bảng.

Quy ước tên thread

TênÝ nghĩa
DThread của downstream, gọi request(n) và cancel().
WThread đang chạy switchTo và giao demand cho nguồn mới (thread "switch").
XThread thứ hai gọi switchTo (resubscribe bất đồng bộ, ví dụ timer của repeatWhen).
EThread đang ở trong callback request() của một nguồn phát đồng bộ.
MMột thread duy nhất làm mọi việc (trường hợp cơ bản).

9 flow (mở bằng trình duyệt)

01 Luồng cơ bản, một threadrequest, phát đồng bộ, itemReceived, switchTo re-entrant.
sequenceđo + đọc code
02 Cuộc đua mất demand (code gốc)Hai thread cùng switch, nhánh SWITCHING không CAS.
sequenceđo: 121 trên 200.000
03 Cùng chồng lấn với PR 3677Mailbox và drain: X để lại việc, W giao demand đúng một lần.
sequenceđo: 0 trên 1.000.000
04 Cancel re-entrant (cùng thread)Cancel ngay trong onNext: code gốc, PR, và gợi ý comment 1.
sequenceđo: 1 so với 1.000.000 item
05 Cancel từ thread khácD cancel khi E đang phát đồng bộ trong request().
sequenceđo: 1.000 so với 1.000.000
06 switchTo trong lúc request() thườngDemand cho nguồn B chạy trên X (gốc) hay trên E (PR).
sequenceđo
07 switchMap: ai gọi switchToThread inner mới hoặc thread inner cũ sau khi onNext xong.
sequenceđọc code
08 Máy trạng thái sourceRequestedidle, SWITCHING, REQUESTED, CANCELLED và đường dẫn tới mất demand.
lifecycleđọc code
09 Luồng drain của PR 3677Lock, mailbox, vòng lặp và vị trí 3 comment.
workflowđọc code

Ma trận kịch bản thread (đã chạy thật)

Mỗi kịch bản dùng latch (không dựa vào timing) và ghi lại thread nào chạy lời gọi xuống nguồn. Ba cột: code gốc, PR 3677, PR 3677 cộng các gợi ý của maintainer (comment 1, 2, 3). Ô màu cam là chỗ khác code gốc.

#Kịch bảnCode gốcPR 3677PR cộng gợi ý
R1request từ D khi callback switch đang chạy trên WD trả về ngay; demand +5 do W giao saugiốnggiống
R2cancel từ D khi callback switch đang chạy trên WD trả về ngay; cancel tới nguồn sau, trên Wgiốnggiống
R3cancel từ D khi callback request thường đang chạy trên Ecancel tới nguồn ngay, trên Dhoãn; cancel tới nguồn trên E sau khi callback xonggiống PR
R4switchTo từ X khi callback request thường đang chạy trên Enguồn B nhận demand ngay, trên XB nhận demand trên E sau khi callback xong; X trả về ngaygiống PR
R5switchTo từ X khi callback switch đang chạy trên WX trả về ngay; W giao demand cho Bgiốnggiống
R6request(1) re-entrant từ onNext, cùng threadnguồn nhận 6 lời gọi, lồng sâu 22 lời gọi, sâu 1 (gộp), cùng tổng demandgiống PR
R7switchTo re-entrant trong callback requestB nhận 1 trên thread Mgiốnggiống
R8cancel sau switchTo chồng lấnchỉ B bị cancel (A: 0, B: 1)cả A và B bị cancel (A: 1, B: 1)chỉ B (như code gốc)
R9cancel re-entrant trong onNext (đo riêng)tới nguồn ngay; nguồn phát 1 itemhoãn; nguồn phát 1.000.000 itemtới nguồn ngay; 1 item, cancel đúng 1 lần
R10cancel từ thread khác khi nguồn phát đồng bộ (đo riêng)dừng ở 1.000 itemphát đủ 1.000.000; chặn 2 giâyvẫn như PR (gợi ý chỉ phủ cùng thread)

Kết luận từ ma trận: PR thay đổi bốn thứ. (a) Thread chạy lời gọi xuống nguồn: demand cho nguồn mới chạy trên thread đang giữ lock (R4). (b) Cancel bị hoãn đến khi callback xong (R3, R9, R10). (c) Request re-entrant được gộp, ít lồng hơn (R6). (d) Nguồn cũ cũng bị cancel (R8). Các gợi ý của maintainer khôi phục (d) và cancel re-entrant (R9), nhưng không khôi phục cancel từ thread khác (R10) và việc dịch chuyển thread (R4). Cả hai kịch bản R9 và R10 được đo bằng test riêng trên cùng ba bản code.

Danh mục trường hợp thread

#Trường hợpBằng chứng
T1Một thread, nguồn đồng bộ, switchTo re-entrant trong callbackĐã đo (R7) và có test trong repo
T2request re-entrant trong onNextĐã đo (R6)
T3cancel re-entrant trong onNextĐã đo (R9)
T4request từ D khi callback switch chạy trên WĐã đo (R1)
T5cancel từ D khi callback switch chạy trên WĐã đo (R2)
T6switchTo từ X khi callback switch chạy trên W, gồm cả phần đuôi chưa thoátĐã đo (R5); cuộc đua ở phần đuôi: 121 trên 200.000 trên code gốc, hang tái hiện 2 trên 2
T7cancel từ D khi callback request thường chạy trên EĐã đo (R3, R10)
T8switchTo từ X khi callback request thường chạy trên EĐã đo (R4)
T9Nguồn nào bị cancel sau switchTo chồng lấnĐã đo (R8)
T10Hai thread D1 và D2 cùng requestChưa đo. Đọc code: code gốc có thể gọi request xuống nguồn đồng thời; PR tuần tự hóa qua lock
T11itemReceived (thread phát) so với switchTo: khả năng nhìn thấy sourceEmittedChưa đo. Dựa vào quan hệ happens-before của tín hiệu tuần tự; PR công bố qua getAndSet volatile
T12request hoặc cancel ném exception trong callbackChưa đo ở đây. PR drain tiếp rồi ném lại; test của PR: requestThrowsAfterSwitchStillDrainsPendingDemand
T13switchMap: cancel đồng thời từ D và từ thread phát ở nhánh lỗiChưa đo. Đọc code PublisherSwitchMap

Mỗi operator: thread nào gọi gì

Operatorrequest / cancelitemReceivedswitchTo chạy trênNguồn kế tiếp bắt đầu từ
ConcatPublisherDthread phát của nguồn hiện tạithread onSubscribe của nguồn kế (cùng thread với onComplete nếu đồng bộ)onComplete của nguồn trước
OnErrorResumePublisherDnhư trênthread onSubscribe của nguồn thay thế (chỉ một lần)onError của nguồn trước
RedoPublisher (repeat, retry)D; cancel còn được gọi trên thread phát khi onNext ném lỗithread phátthread của terminal nếu nguồn đồng bộterminal của nguồn trước, resubscribe ngay
RedoWhenPublisher (repeatWhen, retryWhen)D; cancel còn hủy cả deciderthread phátthread hoàn tất của decider (timer, executor, event loop)decider hoàn tất
PublisherSwitchMapD; cancel còn được gọi trên thread phát ở nhánh lỗithread phát của inner hiện tạithread onSubscribe của inner mới, hoặc thread phát của inner cũ sau khi onNext xongouter onNext

Giới hạn

Nguồn gốc của các file

Các file 01 đến 09 do Archify 3.0.1 (commit 7f483b6, MIT) sinh từ JSON trong thư mục candidates/, chạy bằng finalize --quality showcase: cả 4 cổng (validate, deliver, check, browser-check) đều qua. Kiểm tra cập nhật của Archify đã tắt (ARCHIFY_UPDATE_CHECK_DISABLED=1) nên không có kết nối mạng. Tiêu đề, nhãn và giao diện điều khiển của người xem bằng tiếng Anh là mặc định của Archify (nhãn nội dung bằng tiếng Việt). Trang chỉ mục này không do Archify sinh ra.