[英]Spring Reactor Webflux Scheduler Parallelism
對於完全非阻塞的端到端響應式調用,是否建議顯式調用 publishOn 或 subscribeOn 來切換調度程序? 對於 CPU 消耗或非消耗任務,總是使用並行通量來優化性能是否有利?
值得說明的是,我假設這里的上下文是 Webflux 而不是一般的反應器(因為問題是這樣標記的。)如果我們在不考慮 Webflux 的情況下談論通用反應器用例,那么建議當然會有很大差異。
對於完全非阻塞的端到端響應式調用,是否建議顯式調用 publishOn 或 subscribeOn 來切換調度程序?
一般建議是不要顯式調用這些方法,除非您有理由這樣做。 (在正確的上下文中使用它們並沒有錯,但這樣做“僅僅因為”可能不會帶來任何好處。)
對於 CPU 消耗或非消耗任務,總是使用並行通量來優化性能是否有利?
這取決於您要實現的目標,以及“CPU 消耗”(或 CPU 密集型)任務的含義。 請注意,我在這里談論的是真正的 CPU 密集型任務,而不是阻塞代碼 - 在這種情況下,我理想地將 CPU 密集型部分分配給另一個微服務,使您能夠根據需要進行擴展,與您的 Webflux 服務分開。
使用並行通量(並在並行調度程序上運行)應該使用所有可用的內核來處理數據——這很可能會導致處理得更快。 但請記住,默認情況下,您還為每個內核運行一個事件循環,因此您基本上從事件循環中“竊取”了一些可用容量以實現這一目標。 這是否理想取決於您的用例,但通常不會帶來太多好處。
相反,我推薦兩種方法:
對於完全非阻塞的端到端響應式調用,是否建議顯式調用 publishOn 或 subscribeOn 來切換調度程序?
當您將數據發布到下游時使用publishOn
,而當您從上游消費數據時使用subscribeOn
。 所以這真的取決於你想從事什么樣的工作。
對於 CPU 消耗或非消耗任務,總是使用並行通量來優化性能是否有利?
絕對不是,考慮這個例子:
Flux.range(1, 10)
.parallel(4)
.runOn(Schedulers.parallel())
.sequential()
.elapsed()
.subscribe(i -> System.out.printf(" %s ", i));
上面的代碼完全是浪費,因為i
幾乎會立即被處理。 以下代碼將比上面的代碼執行得更好:
Flux.range(1, 10)
.elapsed()
.subscribe(i -> System.out.printf(" %s ", i));
現在考慮一下:
public static <T> T someMethodThatBlocks(T i, int ms) {
try { Thread.sleep( ms ); }
catch (InterruptedException e) {}
return i;
}
// some method here
Flux.range(1, 10)
.parallel(4)
.runOn(Schedulers.parallel())
.map(i -> someMethodThatBlocks(i, 200))
.sequential()
.elapsed()
.subscribe(i -> System.out.printf(" %s ", i));
output 類似於:
[210,3] [5,1] [0,2] [0,4] [196,6] [0,8] [0,5] [4,7] [196,10] [0,9]
如您所見,第一個響應在210
毫秒后出現,然后是 3 個響應,其間經過的時間接近0
。 該循環一次又一次地重復。 這是您應該使用平行助焊劑的地方。 請注意,創建更多數量的線程並不能保證性能,因為當有更多數量的線程時,上下文切換會增加很多開銷,因此應該在部署之前對代碼進行測試。 如果有很多阻塞調用,每個 cpu 有超過 1 個線程可能會提高性能,但如果調用是 cpu 密集型的,那么每個 cpu 有多個線程會由於上下文切換而降低性能。
所以總而言之,它總是取決於你想要實現什么。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.