加速和最佳实践:将ets用于每个模块的预先计算的数据

如何解决加速和最佳实践:将ets用于每个模块的预先计算的数据

|| ((请原谅我在一个线程中问了多个问题。我认为它们是相关的。) 您好,我想知道,关于每个模块的预编译数据,Erlang中存在哪些最佳实践。 示例:我有一个模块,该模块对先验知识,复杂的正则表达式进行大量运算。 re:compile / 2 \的文档说:“编译一次并执行多次要比每次匹配时的编译效率要高得多”。由于未指定re \的mp()数据类型,因此如果要使用目标无关的光束,则无法在编译时放置它,因此必须在运行时编译RegEx。 ((注意:re:compile / 2只是一个示例。要记住的任何复杂函数都适合我的问题。)) Erlang的模块(可以)具有
-on_load(F/A)
属性,表示加载该模块时应执行一次的方法。这样,我可以将正则表达式放在此方法中进行编译,然后将结果保存在名为
?MODULE
的新ets表中。 在Dan回答后更新。 我的问题是: 如果我正确地理解ets,则将其数据保存在另一个进程中(以不同的形式保存在进程字典中),并且为ets表检索值非常昂贵。 (如果我错了,请证明我错了!)应该将ets中的内容复制到进程字典中以加快速度吗? (请记住:数据永远不会更新。) 将所有数据作为一条记录(而不是许多表项)放入ets / process字典是否有(很大)缺点? 工作示例:
-module(memoization).
-export([is_ipv4/1,fillCacheLoop/0]).
-record(?MODULE,{ re_ipv4 = re_ipv4() }).
-on_load(fillCache/0).

fillCacheLoop() ->
    receive
        { replace,NewData,Callback,Ref } ->
            true = ets:insert(?MODULE,[{ data,{self(),NewData} }]),Callback ! { on_load,Ref,ok },?MODULE:fillCacheLoop();
        purge ->
            ok
    end
.
fillCache() ->
    Callback = self(),Ref = make_ref(),process_flag(trap_exit,true),Pid = spawn_link(fun() ->
        case catch ets:lookup(?MODULE,data) of
            [{data,{TableOwner,_} }] ->
                TableOwner ! { replace,#?MODULE{},self(),Ref },receive
                    { on_load,Result } ->
                        Callback ! { on_load,Result }
                end,ok;
            _ ->
                ?MODULE = ets:new(?MODULE,[named_table,{read_concurrency,true}]),true = ets:insert_new(?MODULE,#?MODULE{}} }]),fillCacheLoop()
        end
    end),receive
        { on_load,Result } ->
            unlink(Pid),Result;
        { \'EXIT\',Pid,Result } ->
            Result
    after 1000 ->
        error
    end
.

is_ipv4(Addr) ->
    Data = case get(?MODULE.data) of
        undefined ->
            [{data,{_,Result} }] = ets:lookup(?MODULE,data),put(?MODULE.data,Result),Result;
        SomeDatum -> SomeDatum
    end,re:run(Addr,Data#?MODULE.re_ipv4)
.

re_ipv4() ->
    {ok,Result} = re:compile(\"^0*\"
            \"([1-9]?\\\\d|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])\\\\.0*\"
            \"([1-9]?\\\\d|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])\\\\.0*\"
            \"([1-9]?\\\\d|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])\\\\.0*\"
            \"([1-9]?\\\\d|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])$\"),Result
.
    

解决方法

        mochiglobal通过编译一个新模块来存储常量来实现这一点。这样做的好处是,内存在各个进程之间共享,在内存中它被复制,而在进程字典中它仅位于该进程的本地。 https://github.com/mochi/mochiweb/blob/master/src/mochiglobal.erl     ,        您还有另一个选择。您可以预先计算正则表达式的编译形式并直接引用它。一种实现方法是使用专门为此目的设计的模块,例如ѭ3:http://dukesoferl.blogspot.com/2009/08/metaprogramming-with-ctexpand.html 您也可以通过动态生成一个模块来滚动自己的函数,该模块具有一个将该值作为常量返回的函数(利用常量池):http://erlang.org/pipermail/erlang-questions/2011-January/ 056007.html 或者甚至可以在shell中运行run4ѭ并将结果复制并粘贴到代码中。粗暴但有效。万一实现发生变化,这将是不可移植的。 需要明确的是:所有这些都利用了常量池,以避免每次都重新计算。但是,当然,这增加了复杂性,并带来了成本。 回到您最初的问题:流程字典的问题是,它只能由自己的流程使用。您确定此模块的功能只能由同一进程调用吗?甚至ETS表都与创建它们的过程相关联(不过,ETS本身并不是使用过程和消息传递来实现的),如果该过程终止,则将失效。     ,ETS不在流程中实现,并且其数据不在单独的流程堆中,但是它的数据确实在所有流程之外的单独区域中。这意味着在读/写ETS表时,必须将数据复制到进程或从进程复制。当然,这有多昂贵,取决于要复制的数据量。这就是为什么我们拥有诸如
ets:match_object
ets:select
之类的功能的原因之一,这些功能允许在复制数据之前使用更复杂的选择规则。 将数据保存在ETS表中的一个好处是,所有进程都可以访问它,而不仅仅是拥有该表的进程。与将数据保存在服务器中相比,这可以使其效率更高。它还取决于您要对数据执行哪种类型的操作。 ETS只是一个数据存储,并提供有限的原子性。在您的情况下,这可能没问题。 您绝对应该将数据保存在单独的记录中,每个记录分别对应一个不同的已编译正则表达式,因为这将大大提高访问速度。然后,您可以直接获取所需的资源,否则将全部获取,然后在所需的资源之后再次搜索。那样的失败使他们无法进入ETS。 尽管您可以执行诸如在
on_load
函数中构建ETS表之类的事情,但对于ETS表却不是一个好主意。这是因为ETS属于进程所有,并且在进程终止时被删除。您永远不会真正知道在哪个过程中调用
on_load
函数。您还应避免执行可能会花费很长时间的操作,因为直到完成模块才将其视为已加载。 生成一个解析转换以静态地将编译res的结果直接插入代码中是一个很不错的主意,尤其是在您re的确是静态定义的情况下。正如动态生成,编译模块并将其加载到系统中的想法一样。同样,如果您的数据是静态的,则可以在编译时生成此模块。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-