在进行项目开发时,有这么一个需求:一个生产者不断产生消息,并将消息异步投递给消费者,异步投递不受任何限制,消费者进程内部将消息写入文件或者通过套接字发送该消息。
看到这个需求,我想也没想,熟练地写下了如下代码:
API:
start_link(FileName, DsgHost, DstPort) ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [FileName, DsgHost, DstPort], []).
deliver_to_file(Msg) -> deliver_to(file, Msg).
deliver_to_net(Msg) -> deliver_to(net, Msg).
deliver_to(Type, Msg) ->
gen_server:cast(?SERVER, {deliver_to, Type, Msg}).
gen_server callback:
init([FileName, DsgHost, DstPort]) ->
{ok, FD} = file:open(FileName,
[binary, raw, read, write, append]),
{ok, Socket} = gen_tcp:connect(DsgHost, DstPort,
[inet, binary, {active, false}, {packet, 4}, {reuseaddr, true}]),
{ok, #state{file = FD, socket = Socket}}.
handle_cast({deliver_to, Type, Msg}, State) ->
handle_msg(Type, Msg, State),
{noreply, State};
handle_msg(Type, Msg, #state{file = File, socket = Socket}) when is_binary(Msg) ->
case Type of
file -> file:write(File, Msg);
net -> gen_tcp:send(Socket, Msg)
end;
handle_msg(Type, Msg, State) ->
handle_msg(Type, term_to_binary(Msg), State).
压测函数编写如下:
deliver_to_with_len_and_times(Type, Len, Times) ->
Msg = makeup_log_by_len(Len),
deliver_to_times(Type, Msg, Times).
deliver_to_times(Type, Msg, Times) when Times > 0 ->
deliver_to(Type, Msg);
deliver_to_times(_Type, _Msg, 0) ->
ok.
makeup_log_by_len(Len) ->
list_to_binary(lists:duplicate(Len, $a)).
函数主要目的为异步地向consumer投递Times个长度为Len的消息。
这段看似简单的代码,却在压测的时候产生了意想不到的效果:当投递消息个数较小时(<1000),handle_msg的处理qps上万,但是随着投递消息数目的增加(>10000),性能却急剧下降,最后仅有300+,使用vmstat、ifstat和top工具观察,磁盘写入和网络发送数据量均不大,但是cpu消耗却不小,这是肿么回事呢?
未完待续...
分享到:
相关推荐
本篇博客“gen_server tasting 之超简单名称服务(续)”主要探讨了如何使用gen_server来构建一个简单的名称服务系统,这是一个在分布式系统中常见的需求,用于存储和查找服务或资源的名称与地址的对应关系。...
在Erlang编程语言中,`gen_server`行为是一个强大的模块,用于构建具有状态的、容错的服务。这篇名为“gen_server tasting 之超简单名称服务”的博客文章可能介绍了如何利用`gen_server`来实现一个简单的命名服务。...
Erlang中的`gen_server`模块是OTP (Open Telecom Platform)设计原则的一部分,它提供了一种标准的方式来实现客户端-服务器架构。gen_server行为模块旨在简化并发处理和错误管理,允许多个客户端共享服务端的资源。它...
Erlang的gen_server是其并发模型的核心组件,它提供了一种强大的状态管理和错误处理机制。而在OCaml语言中,尽管有着自己的并发库如Async,但直接移植或模仿Erlang的gen_server概念可以为OCaml开发者带来更丰富的...
gen_tags.vim, 用来轻松使用 ctags/gtags的vim和neovim的异步插件 gen_tags.vim 为方便用户使用 Vim/ NeoVim,简化了 ctags/ gtags的使用。它用于为你生成和维护多个平台支持的标签,在 Windows/Linux/macOS. 上测试...
ASGI是Python Web服务器和框架之间的一个协议,旨在提供一种更高效、灵活的异步处理方式,与传统的WSGI(Web Server Gateway Interface)相比,ASGI允许Web应用更好地利用多核CPU和非阻塞I/O,从而提高性能和响应...
【标题】"IOCPServerClient源代码"是一个关于网络编程的资源,主要涉及了IO完成端口(IOCP,Input/Output Completion Port)技术在服务器和客户端应用中的实现。IOCP是Windows系统中的一种高效率的异步I/O模型,特别...
标题中的"tcp_server_honorus2_pythonTCP_tcp_tornado_pythonserver_"表明这是一个关于使用Python的Tornado框架构建TCP服务器的项目。Tornado是一个强大的、异步的网络库,特别适合处理高并发的TCP连接,常用于实时...
为了解决这一问题,"gen_tags.vim"应运而生,这是一个专为Vim和Neovim设计的异步插件,旨在简化标签生成流程,提高开发者的生产力。 gen_tags.vim 插件的核心特性是其异步操作。这意味着在生成或更新标签时,编辑器...
传统的阻塞I/O服务器通常需要为每个客户端连接创建一个新的线程,当连接数量增加时,服务器性能会急剧下降。而异步模型下,服务器可以有效地管理这些连接,提高并发处理能力,确保服务的稳定性。 4. **TcpClient....
在Android系统中,串口通信是一种重要的硬件交互方式,它允许设备与外部设备(如传感器、控制器等)进行数据交换。`libserial_port.so`是一个动态链接库,专门用于实现Android平台上的串口驱动功能。这个库文件是C或...
本项目主要探讨了如何利用C#实现基于Socket的TcpClient和TcpServer的异步操作,这对于构建高性能、高并发的网络应用至关重要。下面将详细阐述这两个方面的知识点。 一、TcpClient异步实现 TcpClient类是.NET中的一...
在IT领域,多线程、异步IO以及RS232串口通信是常见的技术概念,尤其在嵌入式系统、物联网(IoT)设备和工业自动化中扮演着重要角色。下面将详细解释这些概念,并结合提供的标题和描述,探讨它们在实际应用中的结合。 ...
通过本案例的学习,我们不仅了解了如何使用Erlang构建高性能的在线IP查询服务,而且还深入学习了OTP的关键行为如gen_server、gen_fsm和gen_event的具体应用。这种实践不仅有助于初学者快速掌握Erlang的核心概念,还...
本资源“C_SERVER_C.rar_c# socket”聚焦于C#语言中的异步套接字服务器和客户端的实现,这对于构建高性能、高并发的网络服务尤其重要。 首先,我们来深入了解C#中的Socket类。Socket是网络编程的基础,它允许程序...
本文将深入探讨如何使用C#基于Socket实现异步TcpServer和TcpClient,以及这两个核心组件的工作原理。 首先,让我们了解TCP(传输控制协议)的基本概念。TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,...
双端口RAM是一种特殊类型的随机访问存储器,它允许数据在两个独立的端口同时读取和写入,这在并行处理、实时系统和多处理器环境中非常有用。描述 "24X240 dual port ram" 暗示我们这里的双端口RAM具有24位数据宽度和...
在Unity3D游戏开发中,异步加载(Asynchronous Loading)是提高用户体验的关键技术之一,尤其是在处理大型场景或大量资源时。本项目提供了一个简洁且漂亮的加载画面,旨在帮助Unity3D学者理解和实现游戏资源的高效...
本文将深入探讨在Windows操作系统中基于I/O完成端口(IOCP,I/O Completion Port)的服务器实现,主要关注`IOCPServer.h`和`IOCPServer.cpp`这两个源文件中的关键概念和技术。I/O完成端口是一种高效率、多线程的I/O...
在C#编程中,异步操作是现代应用开发的关键特性,尤其在处理大量数据或进行I/O密集型任务时,如查询数据库。本主题将深入探讨C#中的异步概念,如何异步查询数据库,以及如何异步处理一行一行加载的数据。 首先,...