I / O แบบไม่ปิดกั้นเร็วกว่า I / O การบล็อกแบบมัลติเธรดจริงหรือไม่ อย่างไร?


119

ฉันค้นหาเว็บเกี่ยวกับรายละเอียดทางเทคนิคบางอย่างเกี่ยวกับการบล็อก I / O และการไม่บล็อก I / O และพบว่ามีหลายคนที่ระบุว่า I / O ที่ไม่ปิดกั้นจะเร็วกว่าการบล็อก I / O ตัวอย่างเช่นในเอกสารนี้

หากฉันใช้การบล็อก I / O แน่นอนว่าเธรดที่ถูกบล็อกในขณะนี้จะไม่สามารถทำอย่างอื่นได้ ... เพราะถูกบล็อก แต่ทันทีที่เธรดเริ่มถูกบล็อก OS สามารถเปลี่ยนไปใช้เธรดอื่นและไม่เปลี่ยนกลับจนกว่าเธรดที่ถูกบล็อกจะมีบางอย่าง ตราบใดที่มีเธรดอื่นในระบบที่ต้องการ CPU และไม่ถูกบล็อกก็ไม่ควรมีเวลาว่างของ CPU อีกต่อไปเมื่อเทียบกับวิธีการไม่บล็อกตามเหตุการณ์หรือไม่?

นอกเหนือจากการลดเวลาที่ CPU ไม่ได้ใช้งานแล้วฉันยังเห็นอีกหนึ่งทางเลือกในการเพิ่มจำนวนงานที่คอมพิวเตอร์สามารถทำได้ในกรอบเวลาที่กำหนด: ลดค่าใช้จ่ายที่แนะนำโดยการสลับเธรด แต่จะทำได้อย่างไร? และค่าใช้จ่ายสูงพอที่จะแสดงเอฟเฟกต์ที่วัดได้หรือไม่? นี่คือแนวคิดเกี่ยวกับวิธีการที่ฉันสามารถวาดภาพได้:

  1. ในการโหลดเนื้อหาของไฟล์แอปพลิเคชันจะมอบหมายงานนี้ให้กับเฟรมเวิร์ก i / o ตามเหตุการณ์โดยส่งผ่านฟังก์ชันเรียกกลับพร้อมกับชื่อไฟล์
  2. เฟรมเวิร์กเหตุการณ์มอบหมายให้กับระบบปฏิบัติการซึ่งตั้งโปรแกรมคอนโทรลเลอร์ DMA ของฮาร์ดดิสก์เพื่อเขียนไฟล์ลงในหน่วยความจำโดยตรง
  3. เฟรมเวิร์กเหตุการณ์อนุญาตให้เรียกใช้โค้ดเพิ่มเติมได้
  4. เมื่อเสร็จสิ้นการคัดลอกจากดิสก์สู่หน่วยความจำตัวควบคุม DMA จะทำให้เกิดการขัดจังหวะ
  5. ตัวจัดการขัดจังหวะของระบบปฏิบัติการจะแจ้งกรอบงาน i / o ตามเหตุการณ์เกี่ยวกับไฟล์ที่โหลดลงในหน่วยความจำอย่างสมบูรณ์ มันทำได้อย่างไร? ใช้สัญญาณ ??
  6. โค้ดที่รันอยู่ในกรอบ i / o ของเหตุการณ์เสร็จสิ้น
  7. เฟรมเวิร์ก i / o ตามเหตุการณ์จะตรวจสอบคิวและเห็นข้อความของระบบปฏิบัติการจากขั้นตอนที่ 5 และดำเนินการเรียกกลับที่ได้รับในขั้นตอนที่ 1

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


5
คำตอบสั้น ๆ : เป็นข้อมูลเพิ่มเติมเกี่ยวกับค่าใช้จ่ายในการมีเธรดต่อการเชื่อมต่อ การไม่บล็อก io ช่วยให้หลีกเลี่ยงการมีเธรดต่อการเชื่อมต่อ
Dan D.

10
การบล็อก IO มีราคาแพงในระบบที่คุณไม่สามารถสร้างเธรดได้มากเท่าที่มีการเชื่อมต่อ ใน JVM คุณสามารถสร้างเธรดได้หลายพันเธรด แต่ถ้าคุณมีการเชื่อมต่อมากกว่า 100,000 ครั้ง? ดังนั้นคุณต้องยึดติดกับโซลูชันแบบอะซิงโครนัส อย่างไรก็ตามมีภาษาที่เธรดไม่แพง (เช่นเธรดสีเขียว) เช่นใน Go / Erlang / Rust ซึ่งไม่ใช่ปัญหาที่จะมี 100.000 เธรด เมื่อจำนวนเธรดมีมากฉันเชื่อว่าการบล็อก IO จะทำให้เวลาตอบสนองเร็วขึ้น แต่นั่นเป็นสิ่งที่ฉันต้องถามผู้เชี่ยวชาญด้วยว่าสิ่งนั้นเป็นจริงหรือไม่
OlliP

@OliverPlow ฉันก็คิดเช่นนั้นเช่นกันเพราะการบล็อก IO มักจะหมายความว่าเราปล่อยให้ระบบจัดการกับ "การจัดการแบบขนาน" แทนที่จะทำเองโดยใช้คิวงานและอื่น ๆ
Pacerier

1
@ DanD. และจะเกิดอะไรขึ้นถ้าค่าใช้จ่ายในการมีเธรดเท่ากับค่าโสหุ้ยของการดำเนินการที่ไม่ปิดกั้น IO? (โดยปกติจะเป็นจริงในกรณีของเธรดสีเขียว)
Pacerier

"การคัดลอกสแต็ก" ไม่เกิดขึ้น เธรดที่แตกต่างกันมีสแต็กที่อยู่ที่แตกต่างกัน แต่ละเธรดมีตัวชี้สแต็กของตัวเองพร้อมกับรีจิสเตอร์อื่น ๆ สวิตช์บริบทบันทึก / กู้คืนสถานะสถาปัตยกรรม (รวมถึงการลงทะเบียนทั้งหมด) แต่ไม่ใช่หน่วยความจำ ระหว่างเธรดในกระบวนการเดียวกันเคอร์เนลไม่จำเป็นต้องเปลี่ยนตารางเพจด้วยซ้ำ
Peter Cordes

คำตอบ:


44

ข้อได้เปรียบที่ใหญ่ที่สุดของ I / O แบบไม่ปิดกั้นหรืออะซิงโครนัสคือเธรดของคุณสามารถทำงานแบบขนานต่อไปได้ แน่นอนคุณสามารถทำได้โดยใช้เธรดเพิ่มเติม ตามที่คุณระบุไว้สำหรับประสิทธิภาพโดยรวม (ระบบ) ที่ดีที่สุดฉันเดาว่าควรใช้ I / O แบบอะซิงโครนัสไม่ใช่หลายเธรด (เพื่อลดการสลับเธรด)

มาดูการใช้งานที่เป็นไปได้ของโปรแกรมเซิร์ฟเวอร์เครือข่ายที่รองรับไคลเอนต์ 1,000 เครื่องที่เชื่อมต่อแบบขนาน:

  1. หนึ่งเธรดต่อการเชื่อมต่อ (สามารถบล็อก I / O ได้ แต่ยังสามารถเป็น I / O ที่ไม่ปิดกั้นได้)
    แต่ละเธรดต้องการทรัพยากรหน่วยความจำ (เช่นหน่วยความจำเคอร์เนลด้วย!) ซึ่งเป็นข้อเสีย และทุกเธรดเพิ่มเติมหมายถึงการทำงานมากขึ้นสำหรับตัวกำหนดตารางเวลา
  2. เธรดเดียวสำหรับการเชื่อมต่อทั้งหมด
    สิ่งนี้ใช้เวลาโหลดจากระบบเนื่องจากเรามีเธรดน้อยลง แต่ยังป้องกันไม่ให้คุณใช้งานเครื่องของคุณได้เต็มประสิทธิภาพเนื่องจากคุณอาจต้องขับโปรเซสเซอร์หนึ่งตัวไปที่ 100% และปล่อยให้โปรเซสเซอร์อื่น ๆ ทั้งหมดไม่ทำงาน
  3. เธรดสองสามเธรดที่แต่ละเธรดจัดการการเชื่อมต่อบางส่วน
    สิ่งนี้ใช้เวลาโหลดจากระบบเนื่องจากมีเธรดน้อยกว่า และสามารถใช้โปรเซสเซอร์ที่มีอยู่ทั้งหมด ใน Windows วิธีการนี้ได้รับการสนับสนุนโดยกระทู้พูล API

แน่นอนว่าการมีเธรดมากขึ้นไม่ใช่ปัญหา อย่างที่คุณทราบฉันเลือกการเชื่อมต่อ / เธรดจำนวนมาก ฉันสงสัยว่าคุณจะเห็นความแตกต่างระหว่างการใช้งานสามอย่างที่เป็นไปได้หากเรากำลังพูดถึงเธรดเพียงโหล (นี่คือสิ่งที่ Raymond Chen แนะนำในบล็อกโพสต์ MSDN Windows มีขีด จำกัด 2,000 เธรดต่อกระบวนการหรือไม่ )

บน Windows โดยใช้ไฟล์ I / O ที่ไม่มีบัฟเฟอร์หมายความว่าการเขียนจะต้องมีขนาดซึ่งเป็นหลายขนาดของเพจ ฉันยังไม่ได้ทดสอบ แต่ดูเหมือนว่าสิ่งนี้อาจส่งผลต่อประสิทธิภาพการเขียนในเชิงบวกสำหรับการเขียนซิงโครนัสและอะซิงโครนัสที่บัฟเฟอร์

ขั้นตอนที่ 1 ถึง 7 ที่คุณอธิบายให้แนวคิดที่ดีว่ามันทำงานอย่างไร บน Windows ระบบปฏิบัติการจะแจ้งให้คุณทราบเกี่ยวกับการเสร็จสิ้นของ I / O แบบอะซิงโครนัส ( WriteFileพร้อมOVERLAPPEDโครงสร้าง) โดยใช้เหตุการณ์หรือการโทรกลับ ฟังก์ชั่นการโทรกลับจะถูกเรียกเช่นเมื่อสายรหัสของคุณWaitForMultipleObjectsExด้วยชุดbAlertabletrue

อ่านเพิ่มเติมบนเว็บ:


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

1
@JavierJ คุณดูเหมือนจะเชื่อว่าถ้า n เธรดทำไฟล์ async IO อีก n เธรดจะถูกสร้างขึ้นเพื่อทำไฟล์บล็อก IO? นี่ไม่เป็นความจริง. ระบบปฏิบัติการมีไฟล์ async รองรับ IO และไม่จำเป็นต้องปิดกั้นเมื่อรอให้ IO เสร็จสมบูรณ์ สามารถจัดคิวคำร้องขอ IO และหากการขัดจังหวะฮาร์ดแวร์ (เช่น DMA) เกิดขึ้นก็สามารถทำเครื่องหมายคำขอว่าเสร็จสิ้นและตั้งค่าเหตุการณ์ที่ส่งสัญญาณไปยังเธรดผู้โทร แม้ว่าจะต้องใช้เธรดเพิ่มเติม แต่ OS ก็สามารถใช้เธรดนั้นสำหรับคำขอ IO หลายรายการจากหลายเธรดได้
Werner Henze

ขอบคุณมันสมเหตุสมผลที่เกี่ยวข้องกับการสนับสนุน IO ของไฟล์ OS async แต่เมื่อฉันเขียนโค้ดสำหรับการใช้งานจริง (จากมุมมองของเว็บ) พูดด้วย Java Servlet 3.0 NIO ฉันยังคงเห็นเธรดสำหรับคำขอและเธรดพื้นหลัง ( async) วนซ้ำเพื่ออ่านไฟล์ฐานข้อมูลหรืออะไรก็ตาม
JavierJ

1
@piyushGoyal ฉัน rewote คำตอบของฉัน ฉันหวังว่าตอนนี้จะชัดเจนขึ้น
Werner Henze

1
บน Windows โดยใช้ไฟล์ I / O แบบอะซิงโครนัสหมายความว่าการเขียนจะต้องมีขนาดซึ่งเป็นหลายขนาดของเพจ - ไม่มันไม่ คุณกำลังคิดถึง I / O ที่ไม่มีบัฟเฟอร์ (มักใช้ร่วมกัน แต่ไม่จำเป็นต้องเป็น)
Harry Johnston

29

I / O ประกอบด้วยการดำเนินการหลายประเภทเช่นการอ่านและเขียนข้อมูลจากฮาร์ดไดรฟ์การเข้าถึงทรัพยากรเครือข่ายการเรียกใช้บริการเว็บหรือการดึงข้อมูลจากฐานข้อมูล ขึ้นอยู่กับแพลตฟอร์มและประเภทของการทำงาน I / O แบบอะซิงโครนัสมักจะใช้ประโยชน์จากฮาร์ดแวร์หรือการสนับสนุนระบบระดับต่ำเพื่อดำเนินการ ซึ่งหมายความว่าจะดำเนินการโดยมีผลกระทบต่อ CPU น้อยที่สุด

ในระดับแอ็พพลิเคชัน I / O แบบอะซิงโครนัสจะป้องกันไม่ให้เธรดต้องรอให้การดำเนินการ I / O เสร็จสมบูรณ์ ทันทีที่การดำเนินการ I / O แบบอะซิงโครนัสเริ่มทำงานเธรดที่เปิดใช้งานและมีการลงทะเบียนการเรียกกลับ เมื่อการดำเนินการเสร็จสิ้นการเรียกกลับจะถูกจัดคิวสำหรับการดำเนินการกับเธรดแรกที่พร้อมใช้งาน

หากการดำเนินการ I / O ดำเนินการพร้อมกันจะทำให้เธรดที่รันอยู่ไม่ทำอะไรเลยจนกว่าการดำเนินการจะเสร็จสิ้น รันไทม์ไม่ทราบว่าการดำเนินการ I / O เสร็จสิ้นเมื่อใดดังนั้นจึงจะให้เวลา CPU เป็นระยะสำหรับเธรดที่รอเวลา CPU ที่เธรดอื่นอาจใช้งานได้

ดังที่ @ user1629468 กล่าวไว้ I / O แบบอะซิงโครนัสไม่ได้ให้ประสิทธิภาพที่ดีกว่า แต่มีความสามารถในการปรับขนาดได้ดีกว่า สิ่งนี้เห็นได้ชัดเมื่อทำงานในบริบทที่มีเธรดจำนวน จำกัด เช่นเดียวกับในกรณีของเว็บแอปพลิเคชัน โดยปกติเว็บแอปพลิเคชันจะใช้เธรดพูลซึ่งกำหนดเธรดให้กับแต่ละคำขอ หากคำขอถูกบล็อกในการดำเนินการ I / O ที่รันเป็นเวลานานมีความเสี่ยงที่จะทำให้เว็บพูลหมดลงและทำให้เว็บแอปพลิเคชันค้างหรือตอบสนองช้า

สิ่งหนึ่งที่ฉันสังเกตเห็นคือ I / O แบบอะซิงโครนัสไม่ใช่ตัวเลือกที่ดีที่สุดเมื่อจัดการกับการดำเนินการ I / O ที่รวดเร็วมาก ในกรณีนี้ประโยชน์ของการไม่ทำให้เธรดไม่ว่างในขณะที่รอให้การดำเนินการ I / O เสร็จสมบูรณ์นั้นไม่สำคัญมากนักและความจริงที่ว่าการดำเนินการเริ่มต้นในเธรดหนึ่งและเสร็จสมบูรณ์ในอีกเธรดหนึ่งจะเพิ่มค่าใช้จ่ายให้กับการดำเนินการโดยรวม

คุณสามารถอ่านรายละเอียดการวิจัยมากขึ้นผมได้ทำเมื่อเร็ว ๆ นี้ในเรื่องของการไม่ตรงกัน I / O เมื่อเทียบกับ multithreading ที่นี่


ฉันสงสัยว่ามันจะคุ้มค่าที่จะสร้างความแตกต่างระหว่างการดำเนินการ I / O ที่คาดว่าจะเสร็จสมบูรณ์และสิ่งที่อาจไม่ [เช่น "รับอักขระถัดไปที่มาถึงพอร์ตอนุกรม" ในกรณีที่อุปกรณ์ระยะไกลอาจหรือไม่ก็ได้ ส่งอะไรก็ได้]. หากคาดว่าการดำเนินการ I / O จะเสร็จสิ้นภายในเวลาที่เหมาะสมอาจทำให้การล้างรีซอร์สที่เกี่ยวข้องล่าช้าจนกว่าการดำเนินการจะเสร็จสิ้น อย่างไรก็ตามหากการดำเนินการอาจไม่เสร็จสมบูรณ์ความล่าช้าดังกล่าวจะไม่สมเหตุสมผล
supercat

@supercat สถานการณ์ที่คุณอธิบายถูกใช้ในแอปพลิเคชันและไลบรารีระดับล่าง เซิร์ฟเวอร์กำลังใช้มันเนื่องจากพวกเขารอการเชื่อมต่อที่เข้ามาอย่างต่อเนื่อง Async I / O ตามที่อธิบายไว้ข้างต้นไม่สามารถใส่ได้ในสถานการณ์นี้เนื่องจากขึ้นอยู่กับการเริ่มต้นการดำเนินการเฉพาะและการลงทะเบียนการเรียกกลับเพื่อให้เสร็จสิ้น ในกรณีที่คุณกำลังอธิบายว่าคุณจำเป็นต้องลงทะเบียนการติดต่อกลับในเหตุการณ์ของระบบและดำเนินการกับการแจ้งเตือนทุกครั้ง คุณกำลังประมวลผลอินพุตอย่างต่อเนื่องแทนที่จะดำเนินการ ดังที่กล่าวไว้ว่าโดยปกติจะทำในระดับต่ำแทบจะไม่เคยปรากฏในแอปของคุณ
Florin Dumitrescu

รูปแบบนี้พบได้บ่อยในแอปพลิเคชันที่มาพร้อมกับฮาร์ดแวร์ประเภทต่างๆ พอร์ตอนุกรมไม่ธรรมดาเหมือนที่เคยเป็น แต่ชิป USB ที่จำลองพอร์ตอนุกรมนั้นค่อนข้างเป็นที่นิยมในการออกแบบฮาร์ดแวร์เฉพาะ อักขระจากสิ่งเหล่านี้ได้รับการจัดการในระดับแอปพลิเคชันเนื่องจากระบบปฏิบัติการจะไม่มีทางรู้ว่าลำดับของอักขระอินพุตหมายถึงเช่นลิ้นชักเก็บเงินถูกเปิดและควรส่งการแจ้งเตือนไปที่ใดที่หนึ่ง
supercat

ฉันไม่คิดว่าส่วนที่เกี่ยวกับต้นทุน CPU ในการบล็อก IO นั้นถูกต้อง: เมื่ออยู่ในสถานะการบล็อกเธรดที่ทริกเกอร์การบล็อก IO จะถูกรอโดยระบบปฏิบัติการและไม่เสียค่าใช้จ่ายช่วง CPU จนกว่า IO จะเสร็จสมบูรณ์หลังจากนั้น ระบบปฏิบัติการ (แจ้งเตือนโดยการขัดจังหวะ) ดำเนินการต่อเธรดที่ถูกบล็อก สิ่งที่คุณอธิบาย (ไม่ว่างรอโดยการสำรวจนาน) ไม่ใช่วิธีการใช้งาน IO บล็อกในเกือบทุกรันไทม์ / คอมไพเลอร์
Lifu Huang

4

เหตุผลหลักในการใช้ AIO คือเพื่อความยืดหยุ่น เมื่อดูในบริบทของเธรดสองสามหัวข้อจะไม่เห็นประโยชน์ที่ชัดเจน แต่เมื่อระบบปรับขนาดเป็น 1,000 เธรด AIO จะให้ประสิทธิภาพที่ดีขึ้นมาก ข้อแม้คือไลบรารี AIO ไม่ควรทำให้เกิดปัญหาคอขวดเพิ่มเติม


4

ในการสันนิษฐานว่ามีการปรับปรุงความเร็วเนื่องจากรูปแบบของการประมวลผลหลายรูปแบบใด ๆ คุณต้องสันนิษฐานไว้ก่อนว่างานที่ใช้ CPU หลายงานกำลังดำเนินการพร้อมกันบนทรัพยากรคอมพิวเตอร์หลายตัว (โดยทั่วไปคือแกนประมวลผล) หรืออื่น ๆ ที่งานทั้งหมดไม่ได้ขึ้นอยู่กับการใช้งานพร้อมกันของ ทรัพยากรเดียวกันนั่นคืองานบางอย่างอาจขึ้นอยู่กับส่วนประกอบย่อยของระบบหนึ่ง (ที่จัดเก็บดิสก์พูด) ในขณะที่บางงานขึ้นอยู่กับอีกอย่างหนึ่ง (รับการสื่อสารจากอุปกรณ์ต่อพ่วง) และงานอื่น ๆ อาจต้องใช้คอร์โปรเซสเซอร์

สถานการณ์แรกมักเรียกว่าการเขียนโปรแกรมแบบ "ขนาน" สถานการณ์ที่สองมักเรียกว่าการเขียนโปรแกรม "พร้อมกัน" หรือ "อะซิงโครนัส" แม้ว่าบางครั้ง "พร้อมกัน" จะใช้เพื่ออ้างถึงกรณีที่อนุญาตให้ระบบปฏิบัติการทำงานหลาย ๆ อย่างแทรกระหว่างกันโดยไม่คำนึงว่าการดำเนินการดังกล่าวจะต้องใช้ วางตามลำดับหรือหากสามารถใช้ทรัพยากรหลายรายการเพื่อให้เกิดการดำเนินการแบบขนาน ในกรณีหลังนี้ "พร้อมกัน" โดยทั่วไปหมายถึงวิธีการเขียนการดำเนินการในโปรแกรมแทนที่จะมองจากมุมมองของการดำเนินงานพร้อมกันจริง

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

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

เป็นประโยชน์ในการจินตนาการถึงกรณีมุมที่ผิดปกติหรือโง่เขลาที่คุณอาจพบเจอ

"อะซิงโครนัส" ไม่จำเป็นต้องทำงานพร้อมกันตัวอย่างเช่นข้างต้นคุณ "อะซิงโครนัส" ดำเนินงานสองงานที่ผูกกับ CPU บนเครื่องที่มีแกนประมวลผลเดียว

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

ดังนั้นทั้ง I / O แบบอะซิงโครนัสหรือมัลติเธรดไม่จำเป็นต้องให้ประสิทธิภาพที่เพิ่มขึ้นในแง่ของเวลาทำงาน พวกเขายังสามารถทำให้สิ่งต่างๆช้าลง

อย่างไรก็ตามหากคุณกำหนดกรณีการใช้งานที่เฉพาะเจาะจงเช่นโปรแกรมเฉพาะที่ทั้งสองทำการเรียกเครือข่ายเพื่อดึงข้อมูลจากทรัพยากรที่เชื่อมต่อกับเครือข่ายเช่นฐานข้อมูลระยะไกลและยังทำการคำนวณที่เชื่อมโยงกับ CPU ในเครื่องคุณสามารถเริ่มให้เหตุผลเกี่ยวกับ ความแตกต่างด้านประสิทธิภาพระหว่างสองวิธีนี้มีข้อสันนิษฐานเฉพาะเกี่ยวกับฮาร์ดแวร์

คำถามที่ต้องถาม: ฉันต้องดำเนินการขั้นตอนการคำนวณกี่ขั้นตอนและมีระบบทรัพยากรที่เป็นอิสระจำนวนเท่าใดในการดำเนินการ มีชุดย่อยของขั้นตอนการคำนวณที่ต้องใช้ส่วนประกอบย่อยของระบบอิสระและจะได้รับประโยชน์จากการทำพร้อมกันหรือไม่ ฉันมีแกนประมวลผลกี่คอร์และค่าใช้จ่ายในการใช้โปรเซสเซอร์หรือเธรดหลายตัวเพื่อทำงานบนคอร์แยกกันคืออะไร

หากงานของคุณพึ่งพาระบบย่อยอิสระเป็นส่วนใหญ่ดังนั้นโซลูชันแบบอะซิงโครนัสอาจจะดี หากจำนวนเธรดที่จำเป็นในการจัดการมีขนาดใหญ่การเปลี่ยนบริบทจึงไม่สำคัญสำหรับระบบปฏิบัติการดังนั้นโซลูชันอะซิงโครนัสเธรดเดียวอาจดีกว่า

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

อีกวิธีหนึ่งคือการอนุญาตให้ระบบปฏิบัติการแทรกแซงการใช้ทรัพยากรเดียวสำหรับงานสองงานต้องไม่เร็วไปกว่าการปล่อยให้งานหนึ่งใช้ทรัพยากรในขณะที่อีกงานหนึ่งรอจากนั้นปล่อยให้งานที่สองเสร็จสิ้นตามลำดับ นอกจากนี้ค่าใช้จ่ายของตัวกำหนดตารางเวลาในการ interleaving หมายถึงในสถานการณ์จริงใด ๆ จะทำให้เกิดการชะลอตัว ไม่สำคัญว่าการใช้งานแบบสอดแทรกจะเกิดขึ้นกับ CPU ทรัพยากรเครือข่ายทรัพยากรหน่วยความจำอุปกรณ์ต่อพ่วงหรือทรัพยากรระบบอื่น ๆ


2

การใช้งาน I / O แบบไม่ปิดกั้นที่เป็นไปได้อย่างหนึ่งคือสิ่งที่คุณพูดโดยมีกลุ่มของเธรดพื้นหลังที่บล็อก I / O และแจ้งเธรดของผู้สร้าง I / O ผ่านกลไกการโทรกลับ อันที่จริงนี่คือวิธีการทำงานของโมดูลAIOใน glibc นี่คือรายละเอียดที่คลุมเครือเกี่ยวกับการใช้งาน

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


2

ขณะนี้ฉันกำลังอยู่ในขั้นตอนการนำ async io ไปใช้บนแพลตฟอร์มแบบฝังโดยใช้โปรโตเธรด การไม่บล็อก io สร้างความแตกต่างระหว่างการทำงานที่ 16000fps และ 160fps ประโยชน์ที่ใหญ่ที่สุดของการไม่บล็อก io คือคุณสามารถจัดโครงสร้างโค้ดของคุณเพื่อทำสิ่งอื่น ๆ ในขณะที่ฮาร์ดแวร์ทำสิ่งนั้นได้ แม้แต่การเริ่มต้นอุปกรณ์ก็สามารถทำได้แบบขนาน

นกนางแอ่น


1

ใน Node มีการเปิดใช้งานเธรดหลายชุด แต่เป็นเลเยอร์ที่อยู่ในเวลารัน C ++

"ใช่แล้ว NodeJS เป็นเธรดเดียว แต่นี่เป็นความจริงครึ่งเดียวจริงๆแล้วมันขับเคลื่อนด้วยเหตุการณ์และเธรดเดียวที่มีคนทำงานเบื้องหลังลูปเหตุการณ์หลักเป็นเธรดเดียว แต่งาน I / O ส่วนใหญ่ทำงานบนเธรดที่แยกกัน เนื่องจาก I / O API ใน Node.js เป็นแบบอะซิงโครนัส / ไม่ปิดกั้นตามการออกแบบเพื่อที่จะรองรับการวนซ้ำของเหตุการณ์ "

https://codeburst.io/how-node-js-single-thread-mechanism-work-understanding-event-loop-in-nodejs-230f7440b0ea

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

https://itnext.io/multi-threading-and-multi-process-in-node-js-ffa5bb5cde98 

คำอธิบาย "โหนดเร็วกว่าเพราะไม่ปิดกั้น ... " เป็นการตลาดเล็กน้อยและนี่เป็นคำถามที่ดี มีประสิทธิภาพและปรับขนาดได้ แต่ไม่ใช่เธรดเดียว


0

การปรับปรุงเท่าที่ผมทราบว่าเป็นที่ไม่ตรงกัน I / O ที่ใช้ (ฉันพูดคุยเกี่ยวกับระบบ MS เพียงเพื่อชี้แจง) เพื่อเรียกว่า I / O พอร์ตเสร็จสิ้น ด้วยการใช้การเรียกแบบอะซิงโครนัสเฟรมเวิร์กจะใช้ประโยชน์จากสถาปัตยกรรมดังกล่าวโดยอัตโนมัติและควรจะมีประสิทธิภาพมากกว่ากลไกเธรดมาตรฐาน ในฐานะประสบการณ์ส่วนตัวฉันสามารถพูดได้ว่าคุณจะรู้สึกได้ว่าแอปพลิเคชันของคุณมีปฏิกิริยามากขึ้นหากคุณต้องการ AsyncCalls แทนที่จะบล็อกเธรด


0

ขอฉันยกตัวอย่างว่า I / O แบบอะซิงโครนัสไม่ทำงาน ฉันกำลังเขียนพร็อกซีที่คล้ายกับด้านล่างโดยใช้ boost :: asio https://github.com/ArashPartow/proxy/blob/master/tcpproxy_server.cpp

อย่างไรก็ตามสถานการณ์ในกรณีของฉันคือข้อความขาเข้า (จากฝั่งไคลเอ็นต์) นั้นเร็วในขณะที่ขาออก (ไปยังฝั่งเซิร์ฟเวอร์) ช้าสำหรับหนึ่งเซสชันเพื่อให้ทันกับความเร็วที่เข้ามาหรือเพื่อเพิ่มปริมาณงานพร็อกซีทั้งหมดเราต้องใช้ หลายเซสชันภายใต้การเชื่อมต่อเดียว

ดังนั้นเฟรมเวิร์ก async I / O นี้ไม่ทำงานอีกต่อไป เราต้องการเธรดพูลเพื่อส่งไปยังเซิร์ฟเวอร์โดยการกำหนดเธรดแต่ละเซสชัน

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