`
wqtn22
  • 浏览: 101068 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

异步gen_server进行port访问时性能严重下降的原因和应对方法(三)典型场景

 
阅读更多

上文解释了问题成因,即进程允许异步投递, 但进程内部有调用port(receive_match)的模式出现 ,现在来看一个典型的场景。

霸爷(yufeng)曾经不建议我们使用error_logger模块记录日志,因为该模块就使用了这个模式。

首先看看error_logger的启动方式:

 

start() ->

    case gen_event:start({local, error_logger}) of

{ok, Pid} ->

   simple_logger(?buffer_size),

   {ok, Pid};

Error -> Error

    end.

可以看出这是一个单进程的gen_event。

 

接着来看看error_logger发送任意一条error日志的方式:

error_logger.erl

error_msg(Format, Args) ->

    notify({error, group_leader(), {self(), Format, Args}}).

notify(Msg) ->

    gen_event:notify(error_logger, Msg).

gen_event.erl

notify(M, Event) -> send(M, {notify, Event}). 

send({global, Name}, Cmd) ->

    catch global:send(Name, Cmd),

    ok;

send(M, Cmd) ->

    M ! Cmd,

    ok.

可以看到error_logger允许异步投递消息。

最后来看看error_logger处理一条日志的过程:

由于error_logger是一个gen_event,其上加载了若干event_handler,此处分析涉及日志文件写的error_logger_file_h:

error_logger_file_h.erl

handle_event(Event, {Fd, File, PrevHandler}) ->

    write_event(Fd, tag_event(Event)),

    {ok, {Fd, File, PrevHandler}};

 

write_event(Fd, {Time, {error, _GL, {Pid, Format, Args}}}) ->

    T = write_time(maybe_utc(Time)),

    case catch io_lib:format(add_node(Format,Pid), Args) of

S when is_list(S) ->

   io:format(Fd, T ++ S, []);

_ ->

   F = add_node("ERROR: ~p - ~p~n", Pid),

   io:format(Fd, T ++ F, [Format,Args])

    end;

 

io.erl

 

format(Io, Format, Args) ->

    o_request(Io, {format,Format,Args}, format).

 

o_request(Io, Request, Func) ->

    case request(Io, Request) of

{error, Reason} ->

   [_Name | Args] = tuple_to_list(to_tuple(Request)),

   {'EXIT',{get_stacktrace,[_Current|Mfas]}} = (catch erlang:error(get_stacktrace)),

   erlang:raise(error, conv_reason(Func, Reason), [{io, Func, [Io | Args]}|Mfas]);

Other ->

   Other

    end.

 

 

request(Pid, Request) when is_pid(Pid) ->

    execute_request(Pid, io_request(Pid, Request));

error_logger_file_h打开日志文件的方式不是raw,此处的文件描述符Io是一个pid()。

 

execute_request(Pid, {Convert,Converted}) ->

    Mref = erlang:monitor(process, Pid),

    Pid ! {io_request,self(),Pid,Converted},

    if

Convert ->

   convert_binaries(wait_io_mon_reply(Pid, Mref));

true ->

   wait_io_mon_reply(Pid, Mref)

    end.

 

wait_io_mon_reply(From, Mref) ->

    receive

{io_reply, From, Reply} ->

   erlang:demonitor(Mref),

   receive 

{'DOWN', Mref, _, _, _} -> true

   after 0 -> true

   end,

   Reply;

{'EXIT', From, _What} ->

   receive

{'DOWN', Mref, _, _, _} -> true

   after 0 -> true

   end,

   {error,terminated};

{'DOWN', Mref, _, _, _} ->

   receive

{'EXIT', From, _What} -> true

   after 0 -> true

   end,

   {error,terminated}

    end.

此处又碰到了熟悉的receive_match模式,调用此模式的位置在error_logger进程内部,将继续引发恶性循环。

除了error_logger,这种模式还在很多地方影响着我们,该肿么办?

未完待续...

 

分享到:
评论

相关推荐

    gen_server tasting 之超简单名称服务

    它可能包含了自己的`gen_server`回调函数,并在启动时通过名称服务进行注册,以便其他部分的系统可以找到并与其交互。 此外,`gen_server`通常与`gen_event`配合使用,后者提供了事件管理功能,可以用来处理日志、...

    gen_tags.vim, 用来轻松使用 ctags/gtags的vim和neovim的异步插件.zip

    gen_tags.vim, 用来轻松使用 ctags/gtags的vim和neovim的异步插件 gen_tags.vim 为方便用户使用 Vim/ NeoVim,简化了 ctags/ gtags的使用。它用于为你生成和维护多个平台支持的标签,在 Windows/Linux/macOS. 上测试...

    C#实现异步连接Sql Server数据库的方法

    在C#编程中,异步连接SQL Server数据库是提高应用程序性能和用户体验的关键技术。这是因为异步操作允许程序在等待数据库响应时执行其他任务,而不是阻塞主线程,从而避免了UI冻结或整体性能下降。本篇文章将深入探讨...

    Python库 | bareASGI_auth_server-4.0.0-py3-none-any.whl

    ASGI是Python Web服务器和框架之间的一个协议,旨在提供一种更高效、灵活的异步处理方式,与传统的WSGI(Web Server Gateway Interface)相比,ASGI允许Web应用更好地利用多核CPU和非阻塞I/O,从而提高性能和响应...

    iocp_server_client 源代码

    【标题】"IOCPServerClient源代码"是一个关于网络编程的资源,主要涉及了IO完成端口(IOCP,Input/Output Completion Port)技术在服务器和客户端应用中的实现。IOCP是Windows系统中的一种高效率的异步I/O模型,特别...

    gen_tags.vim:用于vim和neovim的异步插件,可简化ctagsgtags的使用

    《gen_tags.vim:异步增强Vim与Neovim的ctags与gtags体验》 在编程领域,代码导航工具对于提升开发效率至关重要。Vim 和 Neovim,作为深受程序员喜爱的文本编辑器,提供了强大的ctags和gtags功能,帮助用户快速跳转...

    libserial_port.so Android串口驱动

    这个库文件是C或C++编写的原生代码,通过JNI(Java Native Interface)与Java层进行交互,为Android应用提供访问底层串口硬件的能力。 1. **Android串口驱动原理** Android系统基于Linux内核,因此其串口驱动也...

    Erlang实战

    通过本案例的学习,我们不仅了解了如何使用Erlang构建高性能的在线IP查询服务,而且还深入学习了OTP的关键行为如gen_server、gen_fsm和gen_event的具体应用。这种实践不仅有助于初学者快速掌握Erlang的核心概念,还...

    C# 基于socket实现的异步TcpServer和TcpClient

    本文将深入探讨如何使用C#基于Socket实现异步TcpServer和TcpClient,以及这两个核心组件的工作原理。 首先,让我们了解TCP(传输控制协议)的基本概念。TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,...

    Unity3D多个异步加载场景资源 简洁漂亮的加载画面

    在Unity3D游戏开发中,异步加载(Asynchronous Loading)是提高用户体验的关键技术之一,尤其是在处理大型场景或大量资源时。本项目提供了一个简洁且漂亮的加载画面,旨在帮助Unity3D学者理解和实现游戏资源的高效...

    DSF+同步调用与Flower+DSF异步调用对比测试报告1

    总结来说,对比测试结果表明,Flower的DSF异步调用方式在应对服务延迟和异常时,表现出更好的性能和稳定性,为分布式系统的高可用性和容错性提供了有力保障。在实际应用中,根据系统需求和业务场景选择合适的调用...

    c#实现的mqtt_server服务器端

    6. **云服务器配置**:将MQTT服务器部署到云环境(如AWS、Azure或Google Cloud)时,需要了解云服务提供商的配置和管理方法,例如设置负载均衡、自动扩展和监控。 7. **日志与调试**:为了跟踪和诊断问题,服务器...

    藏经阁-异步场景下的全栈溯源.pdf

    如果不能对异步场景下的全栈溯源进行正确的监控和管理,将会导致系统性能下降、故障率增加、用户体验下降等问题。 异步模式的典型场景: 1. 调用:在异步模式下,一个组件可以异步地调用另一个组件,导致调用关系...

    用WebService进行异步通信

    通过以上两种方法,我们可以有效地实现基于WebService的异步通信,从而提高应用程序的响应性和性能。需要注意的是,尽管这些方法简化了异步编程的过程,但在实际项目中仍然需要考虑诸如错误处理、资源管理等细节问题...

    unity实现场景异步加载并带有加载的进度条

    unity实现场景异步加载并带有加载的进度条,实现场景平稳加载,返回的加载进度为匀速加载。非常适合用在要加载大型场景的情况下。

    MS_SQL_Server集群技术的探讨_格瑞趋势

    至于同步复制和异步复制的选择,同步复制保证了数据在主服务器和从服务器之间的实时一致性,适合对数据完整性要求极高的场景,但可能会牺牲一定的性能。相反,异步复制允许主服务器不等待从服务器确认即可继续处理新...

    flask异步请求研究.rar

    在Python的Web开发框架Flask中,异步请求是一个重要的特性,它允许服务器同时处理多个请求,提高了应用程序的性能和响应速度。本研究主要探讨如何在Flask中实现异步请求,以及它如何帮助实现客户端与服务器端的解耦...

Global site tag (gtag.js) - Google Analytics