用 Fiber 实现 Thread-Per-Message 模式
用 Fiber 实现 Thread-Per-Message 模式
Loom 项目在设计轻量级线程时,充分考量了当前 Java 线程的使用方式,采取的是尽量兼容的态度,所以使用上还是挺简单的。用 Fiber 实现 echo 服务的示例代码如下所示,对比 Thread 的实现,会发现改动量非常小,只需要把 new Thread(()->{…}).start() 换成 Fiber.schedule(()->{}) 就可以了。
final ServerSocketChannel ssc =
ServerSocketChannel.open().bind(
new InetSocketAddress(8080));
// 处理请求
try{
while (true) {
// 接收请求
final SocketChannel sc =
serverSocketChannel.accept();
Fiber.schedule(()->{
try {
// 读 Socket
ByteBuffer rb = ByteBuffer
.allocateDirect(1024);
sc.read(rb);
// 模拟处理请求
LockSupport.parkNanos(2000*1000000);
// 写 Socket
ByteBuffer wb =
(ByteBuffer)rb.flip()
sc.write(wb);
// 关闭 Socket
sc.close();
} catch(Exception e){
throw new UncheckedIOException(e);
}
});
}//while
}finally{
ssc.close();
}
那使用 Fiber 实现的 echo 服务是否能够达到预期的效果呢?可以在 Linux 环境下做一个简单的实验,步骤如下:
- 首先通过
ulimit -u 512
将用户能创建的最大进程数(包括线程)设置为 512; - 启动 Fiber 实现的 echo 程序;
- 利用压测工具 ab 进行压测:ab -r -c 20000 -n 200000 http:// 测试机 IP 地址:8080/
压测执行结果如下:
Concurrency Level: 20000
Time taken for tests: 67.718 seconds
Complete requests: 200000
Failed requests: 0
Write errors: 0
Non-2xx responses: 200000
Total transferred: 16400000 bytes
HTML transferred: 0 bytes
Requests per second: 2953.41 [#/sec] (mean)
Time per request: 6771.844 [ms] (mean)
Time per request: 0.339 [ms] (mean, across all concurrent requests)
Transfer rate: 236.50 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 557 3541.6 1 63127
Processing: 2000 2010 31.8 2003 2615
Waiting: 1986 2008 30.9 2002 2615
Total: 2000 2567 3543.9 2004 65293
发现即便在 20000 并发下,该程序依然能够良好运行。同等条件下,Thread 实现的 echo 程序 512 并发都抗不过去,直接就 OOM 了。
如果你通过 Linux 命令 top -Hp pid
查看 Fiber 实现的 echo 程序的进程信息,你可以看到该进程仅仅创建了 16(不同 CPU 核数结果会不同)个操作系统线程。