ใช้กรณีสำหรับ RxJava schedulers


253

ใน RxJava มี5 ตัวเลือกที่แตกต่างกันให้เลือก:

  1. ทันที () : สร้างและส่งคืน Scheduler ที่ทำงานทันทีบนเธรดปัจจุบัน

  2. trampoline () : สร้างและส่งคืน Scheduler ที่จัดคิวงานบนเธรดปัจจุบันที่จะดำเนินการหลังจากงานปัจจุบันเสร็จสมบูรณ์

  3. newThread () : สร้างและส่งคืน Scheduler ที่สร้างเธรดใหม่สำหรับแต่ละหน่วยงาน

  4. การคำนวณ () : สร้างและส่งคืน Scheduler สำหรับการคำนวณ สามารถใช้สำหรับการวนรอบเหตุการณ์การประมวลผลการเรียกกลับและงานคำนวณอื่น ๆ อย่าทำงานที่ถูกผูกไว้กับ IO บนตัวกำหนดตารางเวลานี้ ใช้ Schedulers io ()แทน

  5. io () : สร้างและส่งคืน Scheduler สำหรับงานที่มีขอบเขต IO การใช้งานได้รับการสนับสนุนโดยเธรดพู Executionor ที่จะเติบโตตามที่ต้องการ สามารถใช้สำหรับการบล็อก IO แบบอะซิงโครนัส อย่าทำงานคำนวณบนตัวกำหนดตารางเวลานี้ ใช้ Schedulers การคำนวณ ()แทน

คำถาม:

3 schedulers แรกนั้นค่อนข้างอธิบายตนเอง แต่ฉันสับสนเล็กน้อยเกี่ยวกับการคำนวณและio

  1. "IO-bound work" คืออะไร? มันใช้สำหรับจัดการกับสตรีม ( java.io) และไฟล์ ( java.nio.files) หรือไม่? มันใช้สำหรับการสืบค้นฐานข้อมูลหรือไม่ ใช้สำหรับดาวน์โหลดไฟล์หรือเข้าถึง REST API หรือไม่
  2. การคำนวณ ()แตกต่างจากnewThread ()อย่างไร มันคือการเรียกการคำนวณทั้งหมด()อยู่ในหัวข้อ (พื้นหลัง) เดียวแทนที่จะเป็นหัวข้อ (พื้นหลัง) ใหม่ในแต่ละครั้ง?
  3. เหตุใดการเรียกการคำนวณ ()เมื่อทำงาน IO จึงไม่ดี
  4. เหตุใดการโทรถึงioจึงไม่ดีเมื่อทำการคำนวณ

คำตอบ:


332

เป็นคำถามที่ดีมากฉันคิดว่าเอกสารสามารถทำรายละเอียดเพิ่มเติมได้บ้าง

  1. io()ได้รับการสนับสนุนจากเธรดพูลที่ไม่ได้ จำกัด และเป็นประเภทที่คุณใช้สำหรับงานที่ไม่ต้องใช้การคำนวณสูงซึ่งเป็นสิ่งที่ไม่ได้ทำให้โหลดบน CPU มากนัก ดังนั้นการโต้ตอบกับระบบไฟล์การโต้ตอบกับฐานข้อมูลหรือบริการบนโฮสต์อื่นจึงเป็นตัวอย่างที่ดี
  2. computation()ได้รับการสนับสนุนโดยเธรดพูลที่มีขอบเขตที่มีขนาดเท่ากับจำนวนตัวประมวลผลที่มีอยู่ หากคุณพยายามกำหนดเวลาการทำงานที่ต้องใช้ CPU มากในแบบขนานมากกว่าตัวประมวลผลที่มี (พูดโดยใช้newThread()) แสดงว่าคุณพร้อมสำหรับค่าใช้จ่ายในการสร้างเธรดและค่าใช้จ่ายในการสลับบริบทเป็นเธรดสำหรับตัวประมวลผล
  3. เป็นการดีที่สุดที่จะออกจากcomputation()การทำงานอย่างเข้มข้นของ CPU เท่านั้นมิฉะนั้นคุณจะไม่ได้รับการใช้งาน CPU ที่ดี
  4. การเรียกio()ใช้งานการคำนวณด้วยเหตุผลที่กล่าวถึงใน 2 io()นั้นไม่ดีและหากคุณกำหนดเวลางานการคำนวณนับพันครั้งio()ในแบบคู่ขนานแต่ละงานพันงานแต่ละงานจะมีเธรดของตัวเองและแข่งขันกับต้นทุนการสลับบริบทของ CPU

5
ผ่านความคุ้นเคยกับแหล่ง RxJava มันเป็นที่มาของความสับสนสำหรับฉันเป็นเวลานานและฉันคิดว่าเอกสารประกอบนั้นจำเป็นต้องได้รับการพัฒนาในเรื่องนี้
Dave Moten

2
@IgorGanapolsky ฉันเดาว่าเป็นสิ่งที่คุณไม่ค่อยอยากทำ การสร้างเธรดใหม่สำหรับทุกหน่วยงานไม่ค่อยเอื้อต่อประสิทธิภาพเนื่องจากเธรดมีราคาแพงในการสร้างและฉีกขาด โดยทั่วไปคุณต้องการใช้เธรดอีกครั้งซึ่งการคำนวณ () และตัวกำหนดเวลาอื่น ๆ ทำ newThread ครั้งเดียวเท่านั้น () อาจมีการใช้งานอย่างถูกกฎหมาย (อย่างน้อยฉันก็นึกได้) กำลังเริ่มงานที่แยกโดดเดี่ยวไม่บ่อยนักใช้งานนาน ถึงอย่างนั้นฉันก็อาจใช้ io () สำหรับสถานการณ์นั้น
tmn

4
คุณช่วยแสดงตัวอย่างที่ trampoline () จะมีประโยชน์หรือไม่ ฉันเข้าใจแนวคิด แต่ฉันไม่สามารถเข้าใจสถานการณ์ที่ฉันใช้ในทางปฏิบัติ มันเป็นตัวกำหนดตารางเวลาเดียวที่ id ยังคงเป็นปริศนาสำหรับฉัน
tmn

32
สำหรับการโทรผ่านเครือข่ายให้ใช้ Schedulers.io () และหากคุณต้องการ จำกัด จำนวนการโทรเครือข่ายพร้อมกันให้ใช้ Scheduler.from (Executors.newFixedThreadPool (n))
Dave Moten

4
คุณอาจคิดว่าการใส่timeoutค่าเริ่มต้นไว้กับcomputation()คุณจะเป็นการบล็อกเธรด แต่ไม่ใช่กรณี ภายใต้ฝาครอบcomputation()ใช้การScheduledExecutorServiceดำเนินการล่าช้าเวลาดังนั้นจะไม่บล็อก เนื่องจากข้อเท็จจริงcomputation()นี้เป็นความคิดที่ดีเพราะหากอยู่ในเธรดอื่นเราจะต้องเสียค่าใช้จ่ายในการเปลี่ยนเธรด
Dave Moten

3

จุดที่สำคัญที่สุดคือทั้งSchedulers.ioและSchedulers.computationได้รับการสนับสนุนโดยเธรดพูลที่ไม่ได้ จำกัด ซึ่งแตกต่างจากที่อื่น ๆ ที่กล่าวถึงในคำถาม คุณลักษณะนี้มีการใช้ร่วมกันโดยSchedulers.from (Executor)ในกรณีที่Executorสร้างขึ้นด้วยnewCachedThreadPool (ไม่ได้ จำกัด ขอบเขตด้วยพูลเธรดเรียกคืนอัตโนมัติ)

ตามที่อธิบายไว้อย่างมากมายในการตอบสนองก่อนหน้าและบทความหลายบทความบนเว็บSchedulers.ioและSchedulers.comจะต้องใช้อย่างระมัดระวังเนื่องจากได้รับการปรับให้เหมาะสมกับประเภทของงานในชื่อของพวกเขา แต่เพื่อจุดของฉันในมุมมองของพวกเขากำลังมีบทบาทสำคัญที่สุดคือการให้ความเห็นพ้องที่แท้จริงให้กับลำธารปฏิกิริยา

ตรงกันข้ามกับความเชื่อของผู้มาใหม่สตรีมแบบตอบสนองไม่ได้เกิดขึ้นพร้อมกันโดยเนื้อแท้ แต่เป็นแบบอะซิงโครนัสและลำดับ ด้วยเหตุผลอย่างนี้Schedulers.ioจะถูกใช้เฉพาะเมื่อการดำเนินการ I / O ถูกบล็อก (เช่น: ใช้คำสั่งการปิดกั้นเช่น Apache IOUtils FileUtils.readFileAsString (... ) ) ดังนั้นจะหยุดเธรดการโทรจนกว่าการดำเนินการจะเป็น เสร็จแล้ว

การใช้วิธีอะซิงโครนัสเช่น Java AsynchronousFileChannel (... ) จะไม่บล็อกเธรดการโทรระหว่างการดำเนินการดังนั้นจึงไม่มีประเด็นในการใช้เธรดแยกต่างหาก อันที่จริงเธรดSchedulers.ioนั้นไม่เหมาะสำหรับการดำเนินการแบบอะซิงโครนัสเนื่องจากพวกเขาไม่ได้ใช้การวนรอบเหตุการณ์และการเรียกกลับจะไม่ถูกเรียก ...

ตรรกะเดียวกันนี้ใช้สำหรับการเข้าถึงฐานข้อมูลหรือการเรียก API ระยะไกล อย่าใช้Schedulers.ioหากคุณสามารถใช้ API แบบอะซิงโครนัสหรือปฏิกิริยาแบบโต้ตอบได้

กลับไปที่การทำงานพร้อมกัน คุณอาจไม่สามารถเข้าถึง async หรือ reactive API เพื่อดำเนินการ I / O แบบอะซิงโครนัสหรือพร้อมกันดังนั้นทางเลือกเดียวของคุณคือการส่งหลายสายในเธรดแยกต่างหาก อนิจจาลำธารปฏิกิริยาเป็นลำดับที่ปลายของพวกเขาแต่ข่าวดีก็คือว่าflatMap ()ผู้ประกอบการสามารถนำเห็นพ้องที่เป็นแกนหลักของพวกเขา

เห็นพ้องต้องได้รับการสร้างขึ้นในการสร้างกระแสโดยปกติจะใช้flatMap ()ผู้ประกอบการ ผู้ให้บริการที่มีประสิทธิภาพนี้สามารถกำหนดค่าให้จัดเตรียมบริบทแบบมัลติเธรดภายใน flatMap ()ฟังก์ชันฝังตัว <T, R> ของคุณ บริบทที่ให้บริการโดยแบบมัลติเธรดตารางเวลาเช่นScheduler.ioหรือScheduler.computation

ค้นหารายละเอียดเพิ่มเติมในบทความเกี่ยวกับ RxJava2 SchedulersและConcurrencyซึ่งคุณจะพบตัวอย่างโค้ดและคำอธิบายโดยละเอียดเกี่ยวกับวิธีใช้ Schedulers ตามลำดับและพร้อมกัน

หวังว่าจะช่วยได้

Softjake


2

โพสต์บล็อกนี้ให้คำตอบที่ยอดเยี่ยม

จากบล็อกโพสต์:

Schedulers.io ()ได้รับการสนับสนุนโดยเธรดพูลที่ไม่มีขอบเขต มันถูกใช้สำหรับงาน I / O ที่ไม่ใช้ CPU มากซึ่งรวมถึงการโต้ตอบกับระบบไฟล์การเรียกเครือข่ายการโต้ตอบของฐานข้อมูล ฯลฯ เธรดพูลนี้มีวัตถุประสงค์เพื่อใช้สำหรับการบล็อก IO แบบอะซิงโครนัส

Schedulers.computation ()ได้รับการสนับสนุนโดยเธรดพูลที่มีขอบเขตที่มีขนาดจนถึงจำนวนตัวประมวลผลที่มีอยู่ มันใช้สำหรับการคำนวณหรืองานที่ใช้ CPU มากเช่นการปรับขนาดรูปภาพการประมวลผลชุดข้อมูลขนาดใหญ่ ฯลฯ โปรดระวัง: เมื่อคุณจัดสรรเธรดการคำนวณมากกว่าคอร์ที่มีอยู่ประสิทธิภาพจะลดลงเนื่องจากการสลับบริบทและการสร้างเธรด เวลาของโปรเซสเซอร์

Schedulers.newThread ()สร้างเธรดใหม่สำหรับแต่ละหน่วยงานที่กำหนดเวลาไว้ ตัวกำหนดตารางเวลานี้มีราคาแพงเนื่องจากมีเธรดใหม่เกิดขึ้นทุกครั้งและไม่มีการใช้ซ้ำ

Schedulers.from (Executionor Executionor)สร้างและส่งคืน Scheduler ที่กำหนดเองซึ่งได้รับการสนับสนุนโดย Exor ที่ระบุ หากต้องการ จำกัด จำนวนเธรดพร้อมกันในเธรดพูลให้ใช้ Scheduler.from (Executors.newFixedThreadPool (n)) สิ่งนี้รับประกันได้ว่าหากภารกิจถูกกำหนดเวลาไว้เมื่อเธรดทั้งหมดถูกครอบครองงานจะถูกจัดคิว เธรดในพูลจะมีอยู่จนกว่าจะปิดอย่างชัดเจน

เธรดหลักหรือAndroidSchedulers.mainThread ()จัดทำโดยไลบรารีส่วนขยาย RxAndroid ไปยัง RxJava เธรดหลัก (หรือที่เรียกว่าเธรด UI) เป็นที่ที่การโต้ตอบของผู้ใช้เกิดขึ้น ควรระมัดระวังไม่ให้โหลดเธรดนี้มากเกินไปเพื่อป้องกัน UI ที่ไม่ตอบสนองต่อการโต้ตอบหรือแย่กว่านั้นโต้ตอบแอปพลิเคชันไม่ตอบสนอง” (ANR)

Schedulers.single ()เป็นของใหม่ใน RxJava 2 ตัวจัดตารางเวลานี้ได้รับการสนับสนุนโดยเธรดเดี่ยวที่ดำเนินงานตามลำดับตามที่ร้องขอ

Schedulers.trampoline ()ดำเนินการงานในลักษณะ FIFO (เข้าก่อนออกก่อน) โดยหนึ่งในเธรดผู้ปฏิบัติงานที่เข้าร่วม มักจะใช้เมื่อใช้การเรียกซ้ำเพื่อหลีกเลี่ยงการเพิ่มจำนวนการโทร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.