对于“进程允许异步投递,但进程内部有调用port(receive_match)的模式出现”这个问题的解决,有这么几个办法:
1从大道理上来讲,需要开发者预估一个进程的处理能力,不要向进程投递过多的消息以致于处理不完,如果处理不完,则需要重新设计,将消息分布到多个进程中处理;
2将异步接收消息的进程与调用port(receive_match)的模式的进程分开;
3拆分向port投递命令的过程,由进程来接收port回传的结果,而不是由模块接收;
4不使用port编写的模块,利用nif重新实现一套;
5其它。
由于本人技术功底尚浅,因此将挑选最常见的两种场景进行分析和解决,这两种场景是文件写和套接字发送。
这里先介绍文件写的场景。
对于1,这确实是一个使用广泛的大道理,能解决一切,却好像又什么都没有解决,开发者需要不断摸索才能做到,我还在摸索中,所以就略过;
对于2,这确实是一个非常通用的解决方案,思路如下:将consumer拆分成两部分,形成两个单独的进程,其中一个进程专用于接收异步消息,另一个进程用于处理消息。接收进程将单条异步消息打包成一个大消息,投递到处理进程处,投递是要检查处理进程的消息队列长度,不能太长,太长会影响处理进程的receive_match性能,也不能太短,太短则会使得处理进程的异步处理流水线不能满载,实测该消息队列长度在8~32范围内较为合适。
优点:实现简单,对file:write没有破坏性;
缺点:需要额外的进程多缓存一次消息,增加了内存和cpu开销,需要消息处理进程处理大包消息,仅为解决问题而存在。
对于3,这种方案需要较高的编程技巧,同时需要对文件访问过程很熟悉,且仅能用于以raw选项打开文件的场景,思路如下:
prim_file:write本身分为两个阶段:port_command和receive_match,因此在写文件时直接调用prim_file:write的前半部分的port_command过程,而不进行下一步的receive_match,并将receive_match放到gen_server的handle_info过程中做。这样又会导致两个新问题:
1 prim_file:write在写过程中产生的错误无法及时处理,由于prim_file:write仅会返回两种错误码ebadf和enospc,前者表示文件打开时没有设置写标识,后者表示文件所处设备没有空间,这两个错误都容易避免;
2 无法继续在同一个进程中调用其它prim_file函数,如read等,因为此时所有从efile port_driver接收的消息都已经紊乱,不能另下一次对read的调用接收到属于它的消息,对于这个问题,一个办法是在调用read等需要消息内容的函数时,进行一次消息同步,即清空消息队列中所有从efile port_driver发来的消息,然后再调用read,在实际实现时,需要使用一个计数器,在每次write的port_command调用时,增加计数器,而每收到一个来自于efile port_driver的write结果消息时,减少计数器,调用其它prim_file函数时,必须接收计数器条write结果歇息时,才能调用其它函数。
优点:工作过程不受receive_match的影响,不需要多份消息拷贝,性能也较好;
缺点:实现复杂,文件访问过程与进程紧耦合,需要对文件写过程较为熟悉,且实现依赖于可能会发生变动的prim_file;
对于4,这几乎是一种完美的解决方法,通过nif解决问题,绕过port体系的影响,riak的bitcask存储引擎有了真正的实现,bitcask_nif.c是它的实现。
优点:不通过port体系,而是通过nif实现文件访问,完全没有receive_match引发的问题;
缺点:不通过port体系,则进程的调度会受到一定程度的影响,原先通过port体系实现,写大量数据的进程会受到惩罚,其reductions也会被bump,但是nif中没有这种自动惩罚机制,需要用户自行实现。
对于5,由于文件数据可以被缓存,因此可以使用如下几种方法:
A打开文件时,设置delayed_write选项,在file:write进入port_driver时,首先将要写的数据缓存到文件port的写缓存中,此时可以令file:write迅速返回,从而加快处理速度,减少进程消息队列堆积量,但该方法终有瓶颈,不能无限制应对消息增加;
B将数据先缓存起来,聚集成大块后,再调用file:write,以减少调用次数,rabbitmq和disk_log模块均使用了这种方法。
对于2、3、4、5A,我都真实的接触过,其中性能比较为2<5A<3<4,向riak的编写者们致敬!
未完待续...
分享到:
相关推荐
它可能包含了自己的`gen_server`回调函数,并在启动时通过名称服务进行注册,以便其他部分的系统可以找到并与其交互。 此外,`gen_server`通常与`gen_event`配合使用,后者提供了事件管理功能,可以用来处理日志、...
gen_tags.vim, 用来轻松使用 ctags/gtags的vim和neovim的异步插件 gen_tags.vim 为方便用户使用 Vim/ NeoVim,简化了 ctags/ gtags的使用。它用于为你生成和维护多个平台支持的标签,在 Windows/Linux/macOS. 上测试...
在C#编程中,异步连接SQL Server数据库是提高应用程序性能和用户体验的关键技术。这是因为异步操作允许程序在等待数据库响应时执行其他任务,而不是阻塞主线程,从而避免了UI冻结或整体性能下降。本篇文章将深入探讨...
文件同步与异步读写是计算机编程中两个关键的概念,主要涉及到I/O操作,尤其是在处理大量数据时。本文将深入探讨这两个概念,并结合提供的VC6.0和VS2005下的实例进行分析。 首先,让我们理解同步和异步读写的基本...
例如,可以使用`@gen.coroutine`装饰器和`yield`关键字来编写异步处理函数。 9. **WebSocket扩展**:Tornado的WebSocket支持使得服务器可以直接与浏览器进行双向通信,常用于实时应用。 10. **错误处理和日志记录*...
这个库文件是C或C++编写的原生代码,通过JNI(Java Native Interface)与Java层进行交互,为Android应用提供访问底层串口硬件的能力。 1. **Android串口驱动原理** Android系统基于Linux内核,因此其串口驱动也...
【标题】"IOCPServerClient源代码"是一个关于网络编程的资源,主要涉及了IO完成端口(IOCP,Input/Output Completion Port)技术在服务器和客户端应用中的实现。IOCP是Windows系统中的一种高效率的异步I/O模型,特别...
此外,gen_tags.vim还支持自动检测文件更改并自动更新标签,确保开发者始终能够访问到最新的代码结构信息。 gen_tags.vim 的实现依赖于 Vimscript,这是一种内置在Vim中的脚本语言,用于扩展和自定义编辑器功能。在...
在IT领域,文件的输入/输出(Input/Output, IO...总结来说,异步IO操作是提高程序性能和响应性的重要手段,尤其在处理文件读写和删除等IO密集型任务时。理解和熟练运用异步编程技术,能够使我们的应用更加高效和健壮。
通过这些技术,我们可以在不阻塞主线程的情况下高效地进行文件传输,提高应用程序的性能和响应性。在实际应用中,还需要考虑错误处理、文件大小限制、安全性等因素,以确保文件传输的可靠性和安全性。
通过本案例的学习,我们不仅了解了如何使用Erlang构建高性能的在线IP查询服务,而且还深入学习了OTP的关键行为如gen_server、gen_fsm和gen_event的具体应用。这种实践不仅有助于初学者快速掌握Erlang的核心概念,还...
本主题将深入探讨如何使用C#实现异步拷贝多个文件到指定目录,并讲解数据线程访问UI线程控件的方法。 首先,让我们关注异步文件拷贝。在C#中,我们可以利用`System.IO.File`类和`System.Threading.Tasks.Task`来...
本文将深入探讨如何使用C#基于Socket实现异步TcpServer和TcpClient,以及这两个核心组件的工作原理。 首先,让我们了解TCP(传输控制协议)的基本概念。TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,...
`jsp异步上传文件`这个主题聚焦于如何利用JavaServer Pages (JSP)、Servlet以及JavaScript的ajaxFileupload.js插件来实现在Web应用中异步上传文件。这种方式可以提供更好的用户体验,因为文件上传不会阻塞页面的其他...
在IT领域,多线程是一种常见且重要的编程技术,它能让我们在单个程序中...通过学习,你可以掌握如何创建和管理线程,以及如何在多线程环境中安全有效地进行串口通信和文件操作,这对提升软件性能和稳定性具有重要意义。
重要的是要考虑到并发访问和资源管理,避免过多的临时文件占用磁盘空间。 6. **通知与下载**:服务器向前端发送一个通知,告诉用户文件已经准备好。通知可以是HTTP响应的一部分,也可以是后续的WebSocket推送。前端...
总结来说,对比测试结果表明,Flower的DSF异步调用方式在应对服务延迟和异常时,表现出更好的性能和稳定性,为分布式系统的高可用性和容错性提供了有力保障。在实际应用中,根据系统需求和业务场景选择合适的调用...
异步加载大尺寸图像文件,如何使用pictureBox的异步方法和事件实现异步操作, //浏览图像 OpenFileDialog MyDlg=new OpenFileDialog(); MyDlg.Filter = "图像文件(JPeg, Gif, Bmp, etc.)|*.jpg;*.jpeg;*.gif;*.bmp...