刚刚在我的 Corei5 2.8GHz 上测试了 Java 的延迟,仅发送/接收单字节,
刚刚生成了 2 个 Java 进程,未使用任务集分配特定的 CPU 核心:
TCP - 25 microseconds
Named pipes - 15 microseconds
现在明确指定核心掩码,例如任务集 1 java Srv or 任务集 2 java CLI:
TCP, same cores: 30 microseconds
TCP, explicit different cores: 22 microseconds
Named pipes, same core: 4-5 microseconds !!!!
Named pipes, taskset different cores: 7-8 microseconds !!!!
so
TCP overhead is visible
scheduling overhead (or core caches?) is also the culprit
同时 Thread.sleep(0) (如 strace 所示,导致执行单个 sched_yield() Linux 内核调用)需要 0.3 微秒 - 因此调度到单核的命名管道仍然有很大的开销
一些共享内存测量:2009 年 9 月 14 日 – Solace Systems 今天宣布,其统一消息平台 API 使用共享内存传输可以实现低于 700 纳秒的平均延迟。
http://solacesystems.com/news/fastest-ipc-messaging/ http://solacesystems.com/news/fastest-ipc-messaging/
附: - 第二天尝试以内存映射文件的形式共享内存,
如果繁忙等待可以接受,我们可以将延迟降低到0.3微秒
使用如下代码传递单个字节:
MappedByteBuffer mem =
new RandomAccessFile("/tmp/mapped.txt", "rw").getChannel()
.map(FileChannel.MapMode.READ_WRITE, 0, 1);
while(true){
while(mem.get(0)!=5) Thread.sleep(0); // waiting for client request
mem.put(0, (byte)10); // sending the reply
}
注意:需要 Thread.sleep(0),以便 2 个进程可以看到彼此的更改
(我还不知道还有其他方法)。如果 2 个进程被迫与任务集相同的核心,
延迟变为 1.5 微秒 - 这是上下文切换延迟
P.P.S - 0.3 微秒是一个不错的数字!以下代码仅花费 0.1 微秒,同时仅进行原始字符串连接:
int j=123456789;
String ret = "my-record-key-" + j + "-in-db";
P.P.P.S - 希望这不是太离题,但最后我尝试用增加一个静态易失性 int 变量来替换 Thread.sleep(0) (这样做时 JVM 碰巧会刷新 CPU 缓存)并获得 - 记录! -Java 到 Java 进程通信延迟 72 纳秒!
然而,当被迫使用相同的 CPU 核心时,易失性递增的 JVM 永远不会相互放弃控制,从而产生恰好 10 毫秒的延迟 - Linux 时间量子似乎是 5 毫秒......所以只有在有空闲核心时才应该使用它 -否则 sleep(0) 更安全。