zmq java 消息阻塞,在 ZeroMQ 的 Response/Request 模式中,服务端回调函数逻辑内调用 fs.readFile 时,为何会阻塞执行?(内有代码)...

Node 版本 10.16.0 ZeroMQ 版本 5.1.0

使用 ZeroMQ 的代码如下:

服务端 /zmq-rep.js

"use strict";

const fs = require("fs");

const zmq = require("zeromq");

const moment = require("moment");

const responder = zmq.socket("rep");

responder.on("message", data => {

let reqData = JSON.parse(data);

let filename = reqData.path;

console.log(`Request received:${filename}`);

fs.readFile(filename, (err, data) => {

if (err) {

throw Error(err);

}

console.log(`Sending response for ${filename} at ${moment().format()}`);

responder.send(

JSON.stringify({

content: data.toString(),

timestamp: moment().format("x"),

pid: process.pid

})

);

});

});

responder.bind("tcp://127.0.0.1:50221", err => {

if (err) {

throw Error(err);

}

console.log("Now listening for requests...");

});

process.on("SIGINT", () => {

console.log("Now closing server...");

responder.close();

});

客户端 /zmq-req.js

"use strict";

const zmq = require("zeromq");

const moment = require("moment");

const filename = process.argv[2];

const request = zmq.socket("req");

request.on("message", data => {

let response = JSON.parse(data);

console.log(

`Fetch file content:${response.content} at ${

response.timestamp

} processed by ${response.pid}`

);

});

request.connect("tcp://127.0.0.1:50221");

for (let i = 1; i <= 5; i++) {

console.log(

`Sending request to get ${filename} for ${i} time(s) at ${moment().format()}`

);

request.send(

JSON.stringify({

path: filename

})

);

}

使用如下方式调用:

# Terminal 1

$ node zmq-rep.js

# Terminal 2

$ node zmq-req.js target.txt

服务端输出如下:

Now listening for requests...

Request received:target.txt

Sending response for target.txt at 2019-07-27T07:36:47+08:00

Request received:target.txt

Sending response for target.txt at 2019-07-27T07:36:47+08:00

Request received:target.txt

Sending response for target.txt at 2019-07-27T07:36:47+08:00

Request received:target.txt

Sending response for target.txt at 2019-07-27T07:36:47+08:00

Request received:target.txt

Sending response for target.txt at 2019-07-27T07:36:47+08:00

客户端输出如下

Sending request to get target.txt for 1 time(s) at 2019-07-27T07:36:47+08:00

Sending request to get target.txt for 2 time(s) at 2019-07-27T07:36:47+08:00

Sending request to get target.txt for 3 time(s) at 2019-07-27T07:36:47+08:00

Sending request to get target.txt for 4 time(s) at 2019-07-27T07:36:47+08:00

Sending request to get target.txt for 5 time(s) at 2019-07-27T07:36:47+08:00

Fetch file content:50221 at 1564184207708 processed by 12984

Fetch file content:50221 at 1564184207734 processed by 12984

Fetch file content:50221 at 1564184207747 processed by 12984

Fetch file content:50221 at 1564184207766 processed by 12984

Fetch file content:50221 at 1564184207794 processed by 12984

可以看到,客户端代码发送请求是非阻塞的,但服务端代码是阻塞的。《 Node.js 8 the right way 》对这个现象的解释是:"Node.js event loop was left spinning while the fs.readFile for each request was being processed."但查阅文档,fs.readFile 本身是非阻塞的,如果这一解释成立的话,fs.readFile 不就是阻塞函数了吗?

我另外写了一份只使用 net 模块进行通讯的代码,现象与使用 ZeroMQ 进行通信不同,在这种情况下,服务端的回调并没有阻塞。

服务端 /tcp-server.js

"use strict";

const fs = require("fs");

const net = require("net");

const moment = require("moment");

const server = net

.createServer(connection => {

console.log("Request received");

connection.on("data", data => {

let reqData = JSON.parse(data);

console.log(`Reading ${reqData.path} at ${moment().format()}`);

fs.readFile(reqData.path, (err, data) => {

connection.write(

JSON.stringify({

content: data.toString(),

timestamp: moment().format()

})

);

});

});

})

.listen({ port: 50221, hostname: "127.0.0.1" })

.on("listening", () => {

console.log("Now listening...");

});

客户端 /tcp-client.js

"use strict";

const net = require("net");

const filename = process.argv[2];

const connectionPool = [];

for (let i = 1; i <= 5; i++) {

connectionPool.push(

net

.createConnection(50221, "127.0.0.1", () => {

console.log(

`Connetcion ${i} established and start fetching file ${filename} on server...`

);

})

.on("data", data => {

console.log(`Receive response:${data}`);

})

);

}

connectionPool.forEach(connection => {

connection.write(

JSON.stringify({

path: filename

})

);

});

process.on("SIGINT", () => {

connectionPool.forEach(connection => {

connection.end();

});

});

调用如下:

# Terminal 1

$ node tcp-server.js

# Terminal 2

$ node tcp-client.js target.txt

客户端输出如下:

Connetcion 1 established and start fetching file target.txt on server...

Connetcion 2 established and start fetching file target.txt on server...

Connetcion 3 established and start fetching file target.txt on server...

Connetcion 4 established and start fetching file target.txt on server...

Connetcion 5 established and start fetching file target.txt on server...

Receive response:{"content":"50221","timestamp":"2019-07-27T07:44:53+08:00"}

Receive response:{"content":"50221","timestamp":"2019-07-27T07:44:53+08:00"}

Receive response:{"content":"50221","timestamp":"2019-07-27T07:44:53+08:00"}

Receive response:{"content":"50221","timestamp":"2019-07-27T07:44:53+08:00"}

Receive response:{"content":"50221","timestamp":"2019-07-27T07:44:53+08:00"}

服务端输出如下:

Now listening...

Request received

Request received

Request received

Request received

Request received

Reading target.txt at 2019-07-27T07:44:53+08:00

Reading target.txt at 2019-07-27T07:44:53+08:00

Reading target.txt at 2019-07-27T07:44:53+08:00

Reading target.txt at 2019-07-27T07:44:53+08:00

Reading target.txt at 2019-07-27T07:44:53+08:00

于是可以看到,不论在服务端还是客户端的 io 都是非阻塞的。

这种不同是否与 ZeroMQ 的实现有关呢?感谢大佬们的回复!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值