Tôi có một máy chủ Node tạo ra một tiến trình con bằng fork()
cách sử dụng IPC. Tại một số thời điểm, đứa trẻ gửi kết quả trở lại cho cha mẹ ở khoảng 10Hz như là một phần của nhiệm vụ dài hạn. Khi tải trọng được chuyển đến process.send()
nhỏ, tất cả đều hoạt động tốt: mọi tin nhắn tôi gửi đều được nhận ~ ngay lập tức và được xử lý bởi phụ huynh.
Tuy nhiên, khi tải trọng là 'Lớn', tôi chưa xác định giới hạn kích thước chính xác, thay vì được phụ huynh nhận ngay lập tức, tất cả các tải trọng được gửi trước và chỉ khi trẻ hoàn thành nhiệm vụ dài hạn thì cha mẹ mới nhận được và xử lý các tin nhắn.
tl; dr trực quan:
Tốt (xảy ra với tải trọng nhỏ):
child: send()
parent: receive()
child: send()
parent: receive()
child: send()
parent: receive()
...
Xấu (xảy ra với tải trọng lớn):
child: send()
child: send()
child: send()
(repeat many times over many seconds)
...
parent: receive()
parent: receive()
parent: receive()
parent: receive()
...
- Đây có phải là một lỗi? (Chỉnh sửa: hành vi chỉ xảy ra trên OS X, không phải Windows hoặc Linux)
- Có cách nào để tránh điều này, ngoài việc cố gắng giữ cho tải trọng IPC của tôi nhỏ không?
Chỉnh sửa 2 : mã mẫu bên dưới sử dụng cả bộ đếm thời gian và bộ lặp để chọn thời điểm gửi bản cập nhật. (Trong mã thực tế của tôi nó cũng có thể gửi một bản cập nhật sau n lần lặp lại, hoặc sau khi vòng lặp đạt được kết quả nhất định.) Là một viết lại ví dụ của mã để sử dụng setInterval
/ setTimeout
thay vì một vòng lặp là một phương sách cuối cùng đối với tôi, vì nó đòi hỏi tôi để loại bỏ các tính năng.
Chỉnh sửa : Đây là mã kiểm tra tái tạo vấn đề. Tuy nhiên, nó chỉ sao chép trên OS X, không phải trên Windows hoặc Linux:
server.js
const opts = {stdio:['inherit', 'inherit', 'inherit', 'ipc']};
const child = require('child_process').fork('worker.js', [], opts);
child.on('message', msg => console.log(`parent: receive() ${msg.data.length} bytes`, Date.now()));
require('http').createServer((req, res) => {
console.log(req.url);
const match = /\d+/.exec(req.url);
if (match) {
child.send(match[0]*1);
res.writeHead(200, {'Content-Type':'text/plain'});
res.end(`Sending packets of size ${match[0]}`);
} else {
res.writeHead(404, {'Content-Type':'text/plain'});
res.end('what?');
}
}).listen(8080);
worker.js
if (process.send) process.on('message', msg => run(msg));
function run(messageSize) {
const msg = new Array(messageSize+1).join('x');
let lastUpdate = Date.now();
for (let i=0; i<1e7; ++i) {
const now = Date.now();
if ((now-lastUpdate)>200 || i%5000==0) {
console.log(`worker: send() > ${messageSize} bytes`, now);
process.send({action:'update', data:msg});
lastUpdate = Date.now();
}
Math.sqrt(Math.random());
}
console.log('worker done');
}
Khoảng 8k vấn đề xảy ra. Ví dụ: khi truy vấn http://localhost:8080/15
vs.http://localhost:8080/123456
/15
worker: send() > 15 bytes 1571324249029
parent: receive() 15 bytes 1571324249034
worker: send() > 15 bytes 1571324249235
parent: receive() 15 bytes 1571324249235
worker: send() > 15 bytes 1571324249436
parent: receive() 15 bytes 1571324249436
worker done
/123456
worker: send() > 123456 bytes 1571324276973
worker: send() > 123456 bytes 1571324277174
worker: send() > 123456 bytes 1571324277375
child done
parent: receive() 123456 bytes 1571324277391
parent: receive() 123456 bytes 1571324277391
parent: receive() 123456 bytes 1571324277393
Có kinh nghiệm trên cả Node v12.7 và v12.12.
run()
có một while
vòng lặp trong đó? Bạn có gợi ý rằng việc chuyển đổi nó setInterval()
sẽ giải quyết vấn đề của tôi? Để trả lời câu hỏi tôi nghĩ bạn đang hỏi: Tôi sử dụng một while
vòng lặp vì chức năng đó là mục đích duy nhất của quy trình nhân viên này và (với tải trọng IPC nhỏ) nó không gây ra bất kỳ vấn đề nào tôi có thể thấy.
setInterval()
giải phóng vòng lặp sự kiện để thực hiện I / O trong nền. Tôi không nói rằng nó chắc chắn sẽ giải quyết vấn đề này, nhưng có vẻ như một lựa chọn kỳ quặc để viết nó theo cách bạn có, chỉ vì bạn có thể.
setTimeout()
hoặc setInterval()
. Sự thay đổi ở đây là tầm thường.
setInterval()
?