Erlang网络编程中的一个特别的函数prim_inet:async_accept/2

为了研究怎么用Erlang写一个游戏服务器,我很幸运的下到了一份英雄远征的服
务器Erlang源码,这两天花了点时间看代码,其中看到做TCP的accept动作时,它
是用的一个函数prim_inet:async_accept/2,这个可跟书上说的不一样(一般来
说书上教的是用gen_tcp:accept/1),于是我google了一下,发现找不到文档,
再翻一下发现已经有不少人问为什么这是一个undocumented的函数,也就是说
Erlang就没想让你去用这个函数,所以文档自然没提供。一般来说undocumented
的函数你是最好别用,因为下一次Erlang更新的时候没准就没这个函数了,或者
参数变了,或者行为变了。总之各种不靠谱的事都可以发生。这个事情可以由
这个帖子  看到。不过,这个帖子还特地说了:However, you might find
prim_inet:async_accept/2 useful.这样又把我们带到了  这个帖子  。在这里,
楼主说看起来这个函数很有趣,很有用,对此提了2个问题,1是为什么这个函数
还是一个undocumented,2是用这个函数安全吗?楼主还给了一篇讲如何用OTP原
理打造一个非阻塞的TCP服务器的 文章

这篇文章中说,虽然prim_inet:async_accept/2是一个undocumented的函数,但
因为他要写一个非阻塞的accept,所以还是会冒险去挖掘它的潜能。因为普通的
函数gen_tcp:accept/1是阻塞的,而现在需要做一个非阻塞的accept,只好用这
个undocumented的函数。

考虑一下这种异步的accept实现可以比同步的accept快多少?当同时有100个并发
的连接请求时,如果同样是有10个进程在做accept,异步的情况能让这100个请求
同时开始被处理。而同步的实现则需要让90个请求等待,先和10个请求accept完
再处理。最撮的那10个请求将要等待9次。(注:这只是简化的思考,实际上有可
能某个请求要等上几十次)再考虑每次的accept,这个我不太清楚,但我想应该
就是建立TCP连接的过程,也就是说client和server之间来回要跑3个包。假设平
均的延时是40ms,那么来回3次是120ms,等待10次差不多是要1秒多。考虑更差的
情况下,可能要等上几十秒,这种就已经是不能忍受的了。从这个角度来说,异
步的accept还是有价值的。

但是,同时有大量并发的连接请求的情况并不会经常出现。以游戏为例,只在刚
开服的时候会遇到这样的问题。正常运行的服务器很少再遇到大量的并发连接请
求。我想说的是,如果我们用100个,甚至1000个阻塞性的accept进程来代替这种
非正式的异步实现,也未尝不可。毕竟1000个进程对于erlang来说还是小case,
而对一个游戏服务器已经够用了。

最后总结一下,一,prim_inet:async_accept/2实现的异步OTP的TCP server在处
理大量并发的情况有优势;二,这种情况可以通过多开一些同步的阻塞性accept
进程在一定程度上克服;三,调用这个函数理论上来说毕竟还是不能完全放心的,
用不用看你的选择了。

最后,如果有时间,可以考虑做一些测试,对这2种情况实际对比。

你可能感兴趣的:(erlang)