setTimeout ทำงานอย่างไรใน Node.JS


112

ฉันเดาว่าเมื่อดำเนินการแล้วมันจะอยู่ในคิว แต่ในคิวมีความมั่นใจว่าจะเรียกใช้หลังจาก X มิลลิวินาทีหรือไม่? หรืองานหนักอื่น ๆ ที่สูงกว่าในคิวจะทำให้ล่าช้า?


14
ไม่มีระบบปฏิบัติการที่ไม่ใช่แบบเรียลไทม์จะทำให้สามารถรับประกันความแม่นยำอย่างจริงจังได้ ทุกสิ่งในระบบสามารถ (และจะ) ขัดขวางกลไกการจับเวลาได้
Pointy

คำตอบ:


174

ความหมายของ setTimeout นั้นใกล้เคียงกับในเว็บเบราว์เซอร์: timeout arg คือจำนวนมิลลิวินาทีขั้นต่ำที่ต้องรอก่อนที่จะดำเนินการไม่ใช่การรับประกัน นอกจากนี้การส่งผ่าน 0 ไม่ใช่ตัวเลขหรือจำนวนลบจะทำให้ต้องรอเป็นจำนวนมิลลิวินาทีขั้นต่ำ ใน Node นี่คือ 1ms แต่ในเบราว์เซอร์อาจมีความยาวได้มากถึง 50ms

เหตุผลนี้คือไม่มีการใช้คำนำหน้าของ JavaScript โดย JavaScript ลองพิจารณาตัวอย่างนี้:

setTimeout(function () {
  console.log('boo')
}, 100)
var end = Date.now() + 5000
while (Date.now() < end) ;
console.log('imma let you finish but blocking the event loop is the best bug of all TIME')

กระแสที่นี่คือ:

  1. กำหนดระยะหมดเวลา 100ms
  2. ไม่ว่างรอ 5000ms
  3. กลับไปที่ลูปเหตุการณ์ ตรวจสอบตัวจับเวลาที่รอดำเนินการและดำเนินการ

หากไม่เป็นเช่นนั้นคุณอาจมี JavaScript "ขัดจังหวะ" อีกหนึ่งบิต เราต้องตั้งค่า mutexes และ semaphors เพื่อป้องกันไม่ให้โค้ดเช่นนี้ยากที่จะให้เหตุผลเกี่ยวกับ:

var a = 100;
setTimeout(function () {
  a = 0;
}, 0);
var b = a; // 100 or 0?

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

นี่คือปีศาจที่จะต่อสู้ได้ดีกว่าความซับซ้อนของใบจองหรือไม่? ขึ้นอยู่กับว่า


20
คุณจะได้รับ +1 สำหรับconsole.logข้อความที่แม่นยำเป็นพิเศษ
Fund Monica's Lawsuit

ฉันชอบวิธีที่คุณใส่ TIME ในสตริงของคุณ อธิบายดีมาก !!!
Alisson

43

แนวคิดของการไม่บล็อกคือการวนซ้ำเป็นไปอย่างรวดเร็ว ดังนั้นในการวนซ้ำสำหรับแต่ละเห็บควรใช้เวลาสั้นพอที่ setTimeout จะแม่นยำภายในความแม่นยำที่เหมาะสม (ปิดโดยอาจจะ <100 ms หรือมากกว่านั้น)

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

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

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

var start = Date.now();

// expecting something close to 500
setTimeout(function(){ console.log(Date.now() - start); }, 500);

// fiddle with the number of iterations depending on how quick your machine is
for(var i=0; i<5000000; ++i){}

เว้นแต่ล่ามจะปรับลูปให้เหมาะสมที่สุด (ซึ่งไม่ได้อยู่ในโครเมี่ยม) คุณจะได้รับบางสิ่งเป็นพัน ถอดห่วงออกแล้วคุณจะเห็นมัน 500 ที่จมูก ...


9

วิธีเดียวที่จะทำให้แน่ใจว่าโค้ดถูกเรียกใช้งานคือวางตรรกะ setTimeout ของคุณในกระบวนการอื่น

ใช้โมดูลกระบวนการลูกเพื่อสร้างโปรแกรม node.js ใหม่ที่ทำตรรกะของคุณและส่งข้อมูลไปยังกระบวนการนั้นผ่านสตรีมบางประเภท (อาจเป็น tcp)

วิธีนี้แม้ว่าโค้ดการบล็อกที่ยาวจะทำงานในกระบวนการหลักของคุณกระบวนการย่อยของคุณได้เริ่มต้นขึ้นแล้วและวาง setTimeout ในกระบวนการใหม่และเธรดใหม่และจะทำงานเมื่อคุณคาดหวัง

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

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


9

setTimeoutเป็นเธรดชนิดหนึ่งซึ่งมีการดำเนินการตามเวลาที่กำหนดและดำเนินการ

setTimeout(function,time_in_mills);

ในที่นี้อาร์กิวเมนต์แรกควรเป็นประเภทฟังก์ชัน ตัวอย่างเช่นหากคุณต้องการพิมพ์ชื่อของคุณหลังจาก 3 วินาทีรหัสของคุณควรเป็นดังนี้

setTimeout(function(){console.log('your name')},3000);

จุดสำคัญที่ต้องจำไว้คือสิ่งที่คุณเคยต้องการที่จะทำโดยใช้setTimeoutวิธีการทำมันภายในฟังก์ชั่น หากคุณต้องการเรียกใช้วิธีอื่นโดยแยกวิเคราะห์พารามิเตอร์บางตัวโค้ดของคุณควรมีลักษณะดังนี้:

setTimeout(function(){yourOtherMethod(parameter);},3000);

8

setTimeout(callback,t)จะใช้ในการเรียกใช้โทรกลับหลังอย่างน้อยเสื้อมิลลิวินาที ความล่าช้าจริงขึ้นอยู่กับปัจจัยภายนอกหลายประการเช่นความละเอียดของตัวจับเวลาระบบปฏิบัติการและภาระของระบบ

ดังนั้นจึงมีความเป็นไปได้ที่จะถูกเรียกเล็กน้อยหลังจากเวลาที่กำหนด แต่จะไม่เคยถูกเรียกมาก่อน

ตัวจับเวลาต้องไม่เกิน 24.8 วัน

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