โหนดมีกระบวนทัศน์ที่แตกต่างกันโดยสิ้นเชิงและเมื่อจับได้อย่างถูกต้องแล้วจะเห็นวิธีการแก้ปัญหาที่แตกต่างกันได้ง่ายขึ้น คุณไม่จำเป็นต้องมีหลายเธรดในแอปพลิเคชันโหนด (1) เนื่องจากคุณมีวิธีการทำสิ่งเดียวกันที่แตกต่างกัน คุณสร้างหลายกระบวนการ แต่มันแตกต่างอย่างมากจากตัวอย่างเช่นวิธีการที่ Prefork mpm ของ Apache Web Server ทำ
สำหรับตอนนี้ลองคิดว่าเรามีแกน CPU เพียงตัวเดียวและเราจะพัฒนาแอปพลิเคชัน (ในรูปแบบของโหนด) เพื่อทำงานบางอย่าง งานของเราคือการประมวลผลไฟล์ขนาดใหญ่ที่ทำงานบนเนื้อหาแบบไบต์ต่อไบต์ วิธีที่ดีที่สุดสำหรับซอฟต์แวร์ของเราคือเริ่มการทำงานจากจุดเริ่มต้นของไฟล์ทำตามแบบทีละไบต์ไปจนจบ
- เฮ้ฮาซันฉันคิดว่าคุณเป็นมือใหม่หรือวัยเรียนตั้งแต่สมัยปู่ของฉัน !!! ทำไมคุณไม่สร้างเธรดและทำให้เร็วขึ้น?
- โอ้เรามีแกน CPU เพียงตัวเดียว
- แล้วไง? สร้างเธรดแมนทำให้เร็วขึ้น!
- มันไม่ได้ผลเช่นนั้น ถ้าฉันสร้างเธรดฉันจะทำให้ช้าลง เนื่องจากฉันจะเพิ่มค่าใช้จ่ายจำนวนมากให้กับระบบเพื่อสลับไปมาระหว่างเธรดพยายามให้เวลากับพวกเขาในระยะเวลาอันสั้นและในกระบวนการของฉันพยายามสื่อสารระหว่างเธรดเหล่านี้ นอกจากข้อเท็จจริงทั้งหมดนี้แล้วฉันยังต้องคิดด้วยว่าฉันจะแบ่งงานเดียวออกเป็นหลาย ๆ ชิ้นที่สามารถทำควบคู่กันได้อย่างไร
- โอเคโอเคฉันเห็นว่าคุณน่าสงสาร มาใช้คอมพิวเตอร์กันเถอะมันมี 32 คอร์!
- ว้าวคุณสุดยอดเพื่อนรักของฉันขอบคุณมาก ฉันรู้สึกทราบซึ้ง!
จากนั้นเรากลับไปทำงาน ตอนนี้เรามี 32 คอร์ cpu ขอบคุณเพื่อนที่ร่ำรวยของเรา กฎที่เราต้องปฏิบัติเพิ่งมีการเปลี่ยนแปลง ตอนนี้เราต้องการใช้ความมั่งคั่งทั้งหมดที่เราได้รับ
ในการใช้หลายคอร์เราต้องหาวิธีแบ่งงานของเราออกเป็นชิ้น ๆ ที่เราสามารถจัดการควบคู่กันได้ ถ้าไม่ใช่โหนดเราจะใช้เธรดสำหรับสิ่งนี้ 32 เธรดหนึ่งชุดสำหรับแต่ละแกนซีพียู อย่างไรก็ตามเนื่องจากเรามี Node เราจะสร้าง 32 Node กระบวนการ
เธรดอาจเป็นทางเลือกที่ดีสำหรับกระบวนการ Node ซึ่งอาจเป็นวิธีที่ดีกว่า แต่เฉพาะในประเภทงานเฉพาะที่มีการกำหนดงานไว้แล้วและเราสามารถควบคุมวิธีจัดการได้อย่างสมบูรณ์ นอกเหนือจากนี้สำหรับปัญหาอื่น ๆ ทุกประเภทที่งานมาจากภายนอกโดยที่เราไม่สามารถควบคุมได้และเราต้องการคำตอบให้เร็วที่สุดวิธีของ Node นั้นเหนือกว่าอย่างไม่มีใครเทียบได้
- เฮซันคุณยังทำงานแบบเธรดเดี่ยวอยู่หรือเปล่า? เกิดอะไรขึ้นกับคุณผู้ชาย? ฉันให้สิ่งที่คุณต้องการ คุณไม่มีข้อแก้ตัวอีกต่อไป สร้างเธรดทำให้ทำงานได้เร็วขึ้น
- ฉันได้แบ่งงานออกเป็นชิ้น ๆ และทุกกระบวนการจะทำงานกับหนึ่งในชิ้นส่วนเหล่านี้ควบคู่กันไป
- ทำไมคุณไม่สร้างเธรด?
- ขออภัยฉันคิดว่ามันใช้งานไม่ได้ คุณสามารถใช้คอมพิวเตอร์ของคุณถ้าคุณต้องการ?
- ไม่เป็นไรฉันใจเย็นฉันไม่เข้าใจว่าทำไมคุณไม่ใช้เธรด?
- ขอบคุณสำหรับคอมพิวเตอร์ :) ฉันแบ่งงานออกเป็นชิ้น ๆ แล้วและฉันสร้างกระบวนการเพื่อทำงานกับชิ้นส่วนเหล่านี้ควบคู่กันไป แกนซีพียูทั้งหมดจะถูกใช้อย่างเต็มที่ ฉันสามารถทำได้ด้วยเธรดแทนที่จะเป็นกระบวนการ แต่โหนดมีวิธีนี้และ Parth Thakkar เจ้านายของฉันต้องการให้ฉันใช้ Node
- โอเคแจ้งให้เราทราบหากคุณต้องการคอมพิวเตอร์เครื่องอื่น : p
ถ้าฉันสร้าง 33 กระบวนการแทนที่จะเป็น 32 ตัวกำหนดตารางเวลาของระบบปฏิบัติการจะหยุดเธรดชั่วคราวเริ่มต้นอีกอันหยุดชั่วคราวหลังจากผ่านไปสักระยะเริ่มกระบวนการอื่นอีกครั้ง ... นี่เป็นค่าใช้จ่ายที่ไม่จำเป็น ฉันไม่ต้องการมัน. ในระบบที่มี 32 คอร์ผมไม่อยากสร้าง 32 โปรเซสเลยด้วยซ้ำ31 ก็ทำได้ดีกว่า เพราะไม่ใช่แค่แอปพลิเคชันของฉันเท่านั้นที่จะทำงานบนระบบนี้ การปล่อยให้มีห้องเล็ก ๆ น้อย ๆ สำหรับสิ่งอื่น ๆ อาจเป็นเรื่องดีโดยเฉพาะอย่างยิ่งถ้าเรามี 32 ห้อง
ผมเชื่อว่าเราอยู่บนหน้าเดียวกันในขณะนี้เกี่ยวกับการใช้หน่วยประมวลผลอย่างเต็มที่สำหรับงาน CPU สูง
- อืมฮะซันฉันขอโทษที่ล้อเลียนคุณนิดหน่อย ฉันเชื่อว่าฉันเข้าใจคุณดีขึ้นแล้ว แต่ยังมีบางอย่างที่ฉันต้องการคำอธิบาย: อะไรคือเรื่องปากต่อปากเกี่ยวกับการรันเธรดนับร้อย ฉันอ่านทุกที่ที่เธรดสร้างได้เร็วและโง่กว่ากระบวนการฟอร์ก? คุณแยกกระบวนการแทนที่จะเป็นเธรดและคุณคิดว่ามันสูงที่สุดที่คุณจะได้รับจาก Node แล้ว Node ไม่เหมาะสมกับงานลักษณะนี้หรือไม่?
- ไม่ต้องกังวลฉันก็เท่เหมือนกัน ทุกคนพูดสิ่งเหล่านี้ดังนั้นฉันคิดว่าฉันเคยได้ยินพวกเขา
- งั้นเหรอ? โหนดไม่ดีสำหรับสิ่งนี้?
- โหนดเหมาะอย่างยิ่งสำหรับสิ่งนี้แม้ว่าเธรดจะดีเช่นกัน สำหรับค่าใช้จ่ายในการสร้างเธรด / กระบวนการ ในสิ่งที่คุณทำซ้ำบ่อย ๆ ทุกๆมิลลิวินาทีมีค่า อย่างไรก็ตามฉันสร้างเพียง 32 โปรเซสและใช้เวลาเล็กน้อย มันจะเกิดขึ้นเพียงครั้งเดียว มันจะไม่สร้างความแตกต่างใด ๆ
- ฉันต้องการสร้างเธรดหลายพันเธรดเมื่อใด
- คุณไม่ต้องการสร้างเธรดนับพัน อย่างไรก็ตามในระบบที่กำลังทำงานที่มาจากภายนอกเช่นเว็บเซิร์ฟเวอร์กำลังประมวลผลคำขอ HTTP หากคุณใช้เธรดสำหรับแต่ละคำขอคุณจะสร้างเธรดจำนวนมากหลายเธรด
- โหนดแตกต่างกันอย่างไร ขวา?
- ใช่แน่นอน นี่คือจุดที่โหนดส่องแสงจริงๆ เช่นเดียวกับเธรดที่เบากว่ากระบวนการมากการเรียกใช้ฟังก์ชันจะเบากว่าเธรดมาก โหนดเรียกใช้ฟังก์ชันแทนการสร้างเธรด ในตัวอย่างของเว็บเซิร์ฟเวอร์คำขอที่เข้ามาทุกครั้งจะทำให้เกิดการเรียกใช้ฟังก์ชัน
- อืมน่าสนใจ; แต่คุณสามารถรันได้เพียงฟังก์ชันเดียวในเวลาเดียวกันหากคุณไม่ได้ใช้หลายเธรด วิธีนี้จะทำงานได้อย่างไรเมื่อมีคำขอจำนวนมากมาถึงเว็บเซิร์ฟเวอร์ในเวลาเดียวกัน
- คุณพูดถูกอย่างสมบูรณ์เกี่ยวกับการทำงานของฟังก์ชันทีละฟังก์ชันไม่ใช้สองฟังก์ชันควบคู่กัน ฉันหมายถึงในกระบวนการเดียวขอบเขตของโค้ดเท่านั้นที่ทำงานในแต่ละครั้ง OS Scheduler ไม่เข้ามาและหยุดฟังก์ชันนี้ชั่วคราวและเปลี่ยนไปใช้ฟังก์ชันอื่นเว้นแต่จะหยุดกระบวนการชั่วคราวเพื่อให้เวลากับกระบวนการอื่นไม่ใช่เธรดอื่นในกระบวนการของเรา (2)
- แล้วโปรเซสจะจัดการ 2 คำขอพร้อมกันได้อย่างไร?
- กระบวนการสามารถรองรับคำขอได้หลายหมื่นรายการในแต่ละครั้งตราบเท่าที่ระบบของเรามีทรัพยากรเพียงพอ (RAM, เครือข่าย ฯลฯ ) การทำงานของฟังก์ชันเหล่านั้นคือความแตกต่างที่สำคัญ
- อืมตอนนี้ฉันควรจะตื่นเต้นไหม?
- อาจจะ :) โหนดทำงานวนซ้ำในคิว ในคิวนี้เป็นงานของเรากล่าวคือการโทรที่เราเริ่มดำเนินการตามคำขอที่เข้ามา ประเด็นสำคัญที่สุดคือวิธีที่เราออกแบบฟังก์ชันให้ทำงาน แทนที่จะเริ่มดำเนินการตามคำขอและให้ผู้โทรรอจนกว่าเราจะเสร็จงานเราก็ยุติการทำงานอย่างรวดเร็วหลังจากทำงานได้ตามจำนวนที่ยอมรับได้ เมื่อเรามาถึงจุดที่เราต้องรอให้ส่วนประกอบอื่นทำงานบางอย่างและคืนค่าให้เราแทนที่จะรอแค่นั้นเราก็ทำหน้าที่ของเราให้เสร็จโดยเพิ่มงานที่เหลือลงในคิว
- ฟังดูซับซ้อนเกินไป?
- ไม่ไม่ฉันอาจฟังดูซับซ้อน แต่ระบบนั้นง่ายมากและมันก็สมเหตุสมผลดี
ตอนนี้ฉันต้องการหยุดการอ้างถึงบทสนทนาระหว่างนักพัฒนาสองคนนี้และจบคำตอบของฉันหลังจากดูตัวอย่างสั้น ๆ ครั้งสุดท้ายว่าฟังก์ชันเหล่านี้ทำงานอย่างไร
ด้วยวิธีนี้เรากำลังทำสิ่งที่ OS Scheduler ทำตามปกติ เราหยุดงานของเราชั่วคราวในบางจุดและปล่อยให้การเรียกใช้ฟังก์ชันอื่น ๆ (เช่นเธรดอื่น ๆ ในสภาพแวดล้อมแบบมัลติเธรด) ทำงานจนกว่าเราจะถึงตาอีกครั้ง สิ่งนี้ดีกว่าการทิ้งงานไปยัง OS Scheduler ซึ่งพยายามให้เวลากับทุกเธรดในระบบ เรารู้ว่าเราทำอะไรได้ดีกว่าที่ OS Scheduler ทำมากและเราคาดว่าจะหยุดเมื่อเราควรหยุด
ด้านล่างนี้เป็นตัวอย่างง่ายๆที่เราเปิดไฟล์และอ่านเพื่อทำงานกับข้อมูล
วิธีซิงโครนัส:
Open File
Repeat This:
Read Some
Do the work
วิธีอะซิงโครนัส:
Open File and Do this when it is ready: // Our function returns
Repeat this:
Read Some and when it is ready: // Returns again
Do some work
ดังที่คุณเห็นฟังก์ชันของเราขอให้ระบบเปิดไฟล์และไม่รอให้เปิด เสร็จสิ้นโดยระบุขั้นตอนต่อไปหลังจากไฟล์พร้อม เมื่อเรากลับมา Node จะเรียกใช้ฟังก์ชันอื่น ๆ บนคิว หลังจากเรียกใช้ฟังก์ชันทั้งหมดลูปเหตุการณ์จะย้ายไปเทิร์นถัดไป ...
โดยสรุปแล้ว Node มีกระบวนทัศน์ที่แตกต่างอย่างสิ้นเชิงกับการพัฒนาแบบหลายเธรด แต่นี่ไม่ได้หมายความว่ามันขาดสิ่งต่างๆ สำหรับงานซิงโครนัส (ซึ่งเราสามารถตัดสินใจลำดับและวิธีการประมวลผล) มันจะทำงานเช่นเดียวกับการทำงานแบบขนานหลายเธรด สำหรับงานที่มาจากภายนอกเช่นการร้องขอไปยังเซิร์ฟเวอร์จะดีกว่า
(1) เว้นแต่คุณจะสร้างไลบรารีในภาษาอื่นเช่น C / C ++ ซึ่งในกรณีนี้คุณยังไม่สร้างเธรดสำหรับแบ่งงาน สำหรับงานประเภทนี้คุณมีเธรดสองเธรดซึ่งหนึ่งในนั้นจะสื่อสารกับโหนดต่อไปในขณะที่อีกเธรดทำงานจริง
(2) ในความเป็นจริงทุกกระบวนการ Node มีหลายเธรดด้วยเหตุผลเดียวกับที่ฉันกล่าวไว้ในเชิงอรรถแรก อย่างไรก็ตามนี่ไม่ใช่วิธีที่เหมือนกับ 1,000 เธรดที่ทำงานคล้ายกัน เธรดพิเศษเหล่านี้มีไว้สำหรับสิ่งต่างๆเช่นการยอมรับเหตุการณ์ IO และเพื่อจัดการการส่งข้อความระหว่างกระบวนการ
อัปเดต (ตอบคำถามที่ดีในความคิดเห็น)
@ มาร์คขอบคุณสำหรับคำวิจารณ์ที่สร้างสรรค์ ในกระบวนทัศน์ของ Node คุณไม่ควรมีฟังก์ชันที่ใช้เวลาในการประมวลผลนานเกินไปเว้นแต่การเรียกอื่น ๆ ทั้งหมดในคิวได้รับการออกแบบให้ทำงานทีละรายการ ในกรณีของงานที่มีราคาแพงในการคำนวณหากเราดูภาพโดยละเอียดแล้วเราจะเห็นว่านี่ไม่ใช่คำถามที่ว่า "เราควรใช้เธรดหรือกระบวนการหรือไม่" แต่มีคำถามว่า "เราจะแบ่งงานเหล่านี้อย่างสมดุลออกเป็นงานย่อยที่เราสามารถรันควบคู่กันได้อย่างไรโดยใช้แกน CPU หลายตัวในระบบ" สมมติว่าเราจะประมวลผลไฟล์วิดีโอ 400 ไฟล์ในระบบที่มี 8 คอร์ หากเราต้องการประมวลผลทีละไฟล์เราจำเป็นต้องมีระบบที่จะประมวลผลส่วนต่างๆของไฟล์เดียวกันซึ่งในกรณีนี้ระบบมัลติเธรดเดี่ยวอาจสร้างได้ง่ายกว่าและมีประสิทธิภาพมากยิ่งขึ้น เรายังคงสามารถใช้ Node สำหรับสิ่งนี้ได้โดยการรันหลายกระบวนการและส่งผ่านข้อความระหว่างกันเมื่อจำเป็นต้องใช้สถานะการแบ่งปัน / การสื่อสาร ดังที่ฉันได้กล่าวไปแล้ววิธีการแบบหลายกระบวนการกับโหนดคือเช่นเดียวกับวิธีการแบบมัลติเธรดในงานประเภทนี้ แต่ไม่มากไปกว่านั้น อีกครั้งอย่างที่ฉันบอกไปก่อนหน้านี้สถานการณ์ที่ Node ส่องคือเมื่อเรามีงานเหล่านี้มาเป็นข้อมูลเข้าสู่ระบบจากหลายแหล่งเนื่องจากการรักษาการเชื่อมต่อจำนวนมากพร้อมกันนั้นเบากว่าใน Node มากเมื่อเทียบกับเธรดต่อการเชื่อมต่อหรือกระบวนการต่อการเชื่อมต่อ ระบบ.
สำหรับการsetTimeout(...,0)
โทร; บางครั้งการหยุดพักระหว่างงานที่เสียเวลาเพื่อให้การโทรในคิวมีส่วนแบ่งการประมวลผลที่จำเป็น การแบ่งงานในรูปแบบต่างๆสามารถช่วยคุณประหยัดจากสิ่งเหล่านี้ได้ แต่ถึงกระนั้นนี่ไม่ใช่การแฮ็ก แต่เป็นเพียงวิธีการทำงานของคิวเหตุการณ์ นอกจากนี้การใช้process.nextTick
เพื่อจุดมุ่งหมายนี้จะดีกว่ามากเนื่องจากเมื่อคุณใช้การsetTimeout
คำนวณและการตรวจสอบเวลาที่ผ่านไปจะเป็นสิ่งที่จำเป็นในขณะที่process.nextTick
เป็นเพียงสิ่งที่เราต้องการจริงๆ: "เฮ้งานกลับไปที่จุดสิ้นสุดของคิวคุณใช้ส่วนแบ่งของคุณแล้ว! "