我写了一个路由器和经销商的例子。
这里是服务器代码,使用路由器 - 经销商接收数据,并向工作人员发送数据以实现负载,当工作人员收到消息时,它将一个Runnable对象放到ExecutorService来计算pi。:
public class MtServer {
private static Logger logger = LoggerFactory.getLogger(MtServer.class);
private static ExecutorService executors = Executors.newFixedThreadPool(2);
static class Worker extends Thread {
private ZMQ.Socket worker;
public Worker(ZMQ.Context context) {
worker = context.socket(ZMQ.REP);
worker.connect("inproc://workers");
}
public void run() {
while(true) {
byte[] recs = worker.recv();
String message = new String(recs);
String threadName = Thread.currentThread().getName();
logger.info("thread[{}] receive [{}]", threadName, message);
executors.submit(new Runnable() {
public void run() {
double pi = 0;
for(int i = 0; i < 100000000; i++) {
pi += Math.pow(-1, i) / (2 * i + 1) * 4;
}
logger.info("pi = {}", pi);
}
});
logger.info("server added [{}]", message);
worker.send(message.getBytes(), 0);
logger.info("server send [{}] back to client", message);
}
}
}
public static void main(String[] args) {
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket clients = context.socket(ZMQ.ROUTER);
clients.bind("tcp://*:5556");
ZMQ.Socket workers = context.socket(ZMQ.DEALER);
workers.bind("inproc://workers");
for(int i = 0; i < 2; ++i) {
Worker worker = new Worker(context);
worker.start();
}
ZMQ.proxy(clients, workers, null);
clients.close();
workers.close();
context.term();
}
}
客户端代码,每100毫秒向服务器发送一条消息:
public class HwClient extends Thread {
private static Logger logger = LoggerFactory.getLogger(HwClient.class);
@Override
public void run() {
String id = UUID.randomUUID().toString().replace("-", "");
ZContext context = new ZContext();
ZMQ.Socket requester = context.createSocket(ZMQ.REQ);
requester.connect("tcp://127.0.0.1:5556");
int seq = 0;
while(!Thread.currentThread().isInterrupted()) {
String message = id + "-" + seq;
requester.send(message.getBytes(), 0);
logger.info("client[{}] send [{}] to server", id, message);
long t1 = System.currentTimeMillis();
byte[] r = requester.recv();
long t2 = System.currentTimeMillis();
logger.info(id + " receive [{}] back from server spend {}ms", message, t2-t1);
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
seq++;
}
context.close();
}
public static void main(String[] args) {
HwClient client = new HwClient();
client.start();
}
}
我的问题是有时客户端recv数据(t2-t1)的延迟太多,在我的例子中它几乎达到8s,并且延迟与计算pi的执行时间有关,如果我减少数量在worker中循环次数,延迟也会减少,但pi在其他线程中计算!
观察日志,大部分时间,当发生很多延迟时,延迟发生在MtServer中的worker.recv(客户端发送数据和工作人员接收数据之间的时间很长),但有时,它发生在提交运行时对象执行者(工作人员接收数据和工作人员发送数据之间的时间很长)。
一些日志:
[test] 2016-02-17 15:19:11:705 INFO [Thread-0] org.test.HwClient.run(26) | client[f11d3f6f6e9b4476a67053828c214c6e] send [f11d3f6f6e9b4476a67053828c214c6e-3] to server
[test] 2016-02-17 15:19:19:563 INFO [pool-2-thread-2] org.test.MtServer$Worker.run(30) | thread[pool-2-thread-2] receive [f11d3f6f6e9b4476a67053828c214c6e-3]
[test] 2016-02-17 15:19:19:563 INFO [pool-2-thread-2] org.test.MtServer$Worker.run(42) | server added [f11d3f6f6e9b4476a67053828c214c6e-3]
[test] 2016-02-17 15:19:19:563 INFO [pool-2-thread-2] org.test.MtServer$Worker.run(44) | server send [f11d3f6f6e9b4476a67053828c214c6e-3] back to client
[test] 2016-02-17 15:19:19:565 INFO [pool-1-thread-2] org.test.MtServer$Worker$1.run(38) | pi = 3.141592643589326
[test] 2016-02-17 15:19:19:565 INFO [pool-1-thread-1] org.test.MtServer$Worker$1.run(38) | pi = 3.141592643589326
[test] 2016-02-17 15:19:19:563 INFO [Thread-0] org.test.HwClient.run(30) | f11d3f6f6e9b4476a67053828c214c6e receive [f11d3f6f6e9b4476a67053828c214c6e-3] back from server spend 7858ms
[test] 2016-02-17 15:19:19:666 INFO [Thread-0] org.test.HwClient.run(26) | client[f11d3f6f6e9b4476a67053828c214c6e] send [f11d3f6f6e9b4476a67053828c214c6e-4] to server
[test] 2016-02-17 15:19:19:666 INFO [pool-2-thread-1] org.test.MtServer$Worker.run(30) | thread[pool-2-thread-1] receive [f11d3f6f6e9b4476a67053828c214c6e-4]
任何人都可以帮助我吗?感谢。