Trong ngữ cảnh của các công cụ Javascript phía máy chủ, I / O không chặn hoặc I / O không đồng bộ là gì? Tôi thấy điều này được đề cập như một lợi thế so với việc triển khai phía máy chủ Java.
Trong ngữ cảnh của các công cụ Javascript phía máy chủ, I / O không chặn hoặc I / O không đồng bộ là gì? Tôi thấy điều này được đề cập như một lợi thế so với việc triển khai phía máy chủ Java.
Câu trả lời:
Thực thi đồng bộ thường đề cập đến việc thực thi mã theo trình tự. Thực thi không đồng bộ đề cập đến thực thi không chạy trong chuỗi nó xuất hiện trong mã. Trong ví dụ sau, hoạt động đồng bộ làm cho các cảnh báo bắn theo thứ tự. Trong hoạt động không đồng bộ, trong khi alert(2)
dường như thực thi thứ hai, thì không.
Đồng bộ: 1,2,3
alert(1);
alert(2);
alert(3);
Không đồng bộ: 1,3,2
alert(1);
setTimeout(() => alert(2), 0);
alert(3);
Chặn liên quan đến các hoạt động chặn thực hiện thêm cho đến khi hoạt động đó kết thúc. Không chặn đề cập đến mã không chặn thực thi. Trong ví dụ đã cho, localStorage
là một hoạt động chặn vì nó ngăn chặn việc thực thi để đọc. Mặt khác, fetch
là một hoạt động không chặn vì nó không bị đình trệ alert(3)
khi thực hiện.
// Blocking: 1,... 2
alert(1);
var value = localStorage.getItem('foo');
alert(2);
// Non-blocking: 1, 3,... 2
alert(1);
fetch('example.com').then(() => alert(2));
alert(3);
Một lợi thế của các hoạt động không đồng bộ, không đồng bộ là bạn có thể tối đa hóa việc sử dụng một CPU cũng như bộ nhớ.
Một ví dụ về các hoạt động chặn, đồng bộ là cách một số máy chủ web như Java hoặc PHP xử lý các yêu cầu IO hoặc mạng. Nếu mã của bạn đọc từ một tệp hoặc cơ sở dữ liệu, mã của bạn sẽ "chặn" mọi thứ sau khi nó thực thi. Trong khoảng thời gian đó, máy của bạn đang giữ bộ nhớ và thời gian xử lý cho một luồng không làm gì cả .
Để phục vụ các yêu cầu khác trong khi luồng đó bị đình trệ phụ thuộc vào phần mềm của bạn. Những gì hầu hết các phần mềm máy chủ làm là sinh ra nhiều luồng hơn để phục vụ các yêu cầu bổ sung. Điều này đòi hỏi nhiều bộ nhớ tiêu thụ và xử lý nhiều hơn.
Các máy chủ không đồng bộ, không chặn - như các máy chủ được tạo trong Node - chỉ sử dụng một luồng để phục vụ tất cả các yêu cầu. Điều này có nghĩa là một thể hiện của Node tận dụng tối đa một luồng. Các nhà sáng tạo đã thiết kế nó với tiền đề rằng các hoạt động I / O và mạng là nút cổ chai.
Khi các yêu cầu đến máy chủ, chúng được phục vụ từng cái một. Tuy nhiên, khi mã được phục vụ cần truy vấn DB chẳng hạn, nó sẽ gửi cuộc gọi lại đến hàng đợi thứ hai và luồng chính sẽ tiếp tục chạy (nó không chờ). Bây giờ khi hoạt động DB hoàn thành và trả về, cuộc gọi lại tương ứng đã rút ra khỏi hàng đợi thứ hai và xếp hàng trong hàng thứ ba nơi chúng đang chờ thực thi. Khi động cơ có cơ hội thực hiện một cái gì đó khác (như khi ngăn xếp thực thi bị xóa), nó chọn một cuộc gọi lại từ hàng đợi thứ ba và thực hiện nó.
var startTime = new Date().getTime();
var getEndTime = () => {
var tempEndTime = new Date().getTime();
var second = (tempEndTime - startTime)/1000
return `took ${second} sec...to finish\n`
}
console.log('1: start App', getEndTime())
setTimeout(()=>{
console.log('2: setTimeout', getEndTime())
}, 1000)
console.log('3: End App', getEndTime())
// console -> Process Order: 1 -> 3 -> 2