2021 年你需要知道的关于 Erlang 的一切
- admin
- 07 Jan 2024
今天,我们将看一个相当古老且有些古怪的东西。 你们大多数人可能没有注意到的语言。 虽然 Erlang 不像某些现代编程语言那样流行,但它安静地运行着 WhatsApp 和微信等每天为大量用户提供服务的应用程序。 在这篇文章中,我将告诉你关于这门语言的更多事情、它的历史,以及你是否应该考虑自己学习它。 ## 什么是 Erlang,它在哪里使用? Erl
Read More在本教程中,我将介绍作为 Erlang 开发人员在日常生活中使用最多的工具。入选的所有或大部分工具都具有以下特征:
与许多其他语言一样,与 Erlang VM 交互的最常见方式是通过 Erlang shell。您可以使用它来测试代码、学习如何使用 Erlang 以及调试生产系统。Erlang shell 是一个强大的东西,但是您可以使用下面我将向您展示的三个工具来为其添加更多功能。
一般来说,要在 Erlang 中评估模块之外的函数,您必须在它们的名称前面加上相应的模块名称。例如,如果要汇总一个列表,则必须执行以下操作:
1> lists:sum([1, 2, 3]).
6
2>
但是您会注意到,对于 shell 中的某些函数,您不需要显式定义。例如:
1> c(your_module).
{ok,your_module}
2> h().
1: c(your_module)
-> {ok,your_module}
ok
3> e(1).
{ok,your_module}
4>
这些功能在哪里?它们在shell_default模块中定义。您也可以添加自己的默认函数。为此,您必须创建并加载一个名为user_default. 例如,我喜欢在使用 Erlang shell 时运行 bash 命令;我不想只是为了复制文件就离开shell。Erlang/OTP 为您提供了一个函数来执行此操作:os:cmd/1,但这不会打印出您的命令的输出。相反,此命令将输出作为字符串返回。您必须打印字符串才能正确查看输出。
因此,使用user_default,我将以下行添加到我的user_default.erl文件中:
-module(user_default).
-export([cmd/1].
cmd(Cmd) -> io:format("~s~n", [os:cmd(Cmd)]).
现在我可以在shell中运行、执行和打印os:cmd/1的结果:
1> c(user_default).
{ok, user_default}
2> cmd("cat user_default.erl").
-module(user_default).
-export([cmd/1].
cmd(Cmd) -> io:format("~s~n", [os:cmd(Cmd)]).
ok
3>
但是,我必须在我打开的每一个shell中手动加载user_default。/.erlang可以解决这种状况!/.erlang是一个与bash中的~/.bashrc一样工作的文件。启动时,shell 读取~/.erlang并执行其中找到的每个表达式,就好像它们被输入到 shell 一样。
因此,我在该文件中添加了以下几行:
UD = "/path/to/my/user_default".
2shell_default:c(UD).
我的~/.erlang实际上比这个更复杂,但是shell_default应该给你了要修改的要点。现在,我打开的每个 shell 都支持cmd/1.
Erlang shell 中最烦人的事情之一是它不能很好地跟踪命令历史。事实上,默认设置会在关闭 shell 时清除所有命令历史记录。我已经看到许多开发人员通过使用一个记录本来记录 erlang 表达式解决此限制,他们每次都从中复制并粘贴到控制台中。(他们中的一些人使用user_default and/or ~/.erlang。)
但是,这仍然不是一个真正的解决方案,对吧?为了正确解决这个问题,在安装新版本的 Erlang/OTP 之后,我安装了erlang-history。这是对 Erlang/OTP 发行版的一个非常微小的几乎看不见的 hack,其目的很简单:跟踪您以前在 Erlang shell 中的命令并让您重用它们。简单,但非常有用。
一旦您跳过简单的示例并进入 OTP 应用程序的领域,使用可以帮助您组织代码、管理依赖项、构建版本、运行测试等的构建工具会更好。
使用 Erlang 时,您可以接受Makefile或尝试尽可能远离它。
如果使用 Makefiles 构建和管理您的项目对您来说很自然,您可能会喜欢erlang.mk。erlang.mk基本上是一个大的 Makefile 脚本,您可以将其包含在您自己的 Makefile 中,例如:
PROJECT=your_app
include erlang.mk
这样,您就可以访问许多命令,例如
您可以使用$ make help找到整个列表,当然,您可以通过扩展您的 Makefile 来添加更多。
erlang.mk还提供了一个插件基础设施,您可以在其中添加构建工具,例如hexer.mk或elvis.mk。
更好的一点erlang.mk为构建几乎所有现有的 Erlang 库提供了必要的支持,无论库所有者使用什么工具来维护它。您可以在您的存储库erlang.mk中包含使用rebar、rebar3、erlang.mk(和预期的一致:P)、 ad-hoc Makefiles和其他构建的应用程序。您可以从github、hex.pm、bitbucket、您的本地文件系统和许多其他地方下载依赖。显然erlang.mk使 Erlang 更加通用。
现在,如果 Makefile 不是你的菜,并且你更喜欢使用由 Erlang/OTP 团队赞助的官方构建工具(自 2016 年 3 月起),那么rebar3就是你的选择。
rebar3完全用 Erlang 编写,其想法是您可以在不向项目中添加任何 Makefile 的情况下使用它。
将其安装到系统中后,您应该在项目的根文件夹中添加一个rebar.config文件。一个最小化范例看起来像这样(尽管下面的选项也是可选的):
{deps, []}.
{erl_opts, [debug_info]}.
{cover_enabled, true}.
您可以在此处找到您可以指定的所有选项的列表。然后,您可以在 shell 中运行如下命令:
当然,$ rebar3 help会为您提供所有可用命令的列表。而且,就像erlang.mk,rebar3也可以通过plugins进行扩展。
最好的事情之一是,rebar3通过使用rebar.lock,它提供了可重复的构建。这样,一旦您确定您的项目按预期工作,您就可以确保无论您编译多少次或在多少个不同的地方编译它,它都会按预期工作。
我个人已经在网上(在采访和博客文章中)多次说过保持高质量代码的重要性(尤其是在你从事开源项目的情况下)。Erlang 附带了几个工具可以帮助你解决这个问题。Erlang 工具甚至可以帮助您检测在运行时可能会发现的错误……无需运行您的系统!
Dialyzer是一个静态分析工具,可以帮助您识别代码中的类型不一致,例如,当您将 binary()作为参数传递给需要string()的函数时。这曾经是一个非常非常慢的工具,但它已经被高度优化,现在运行流畅,特别是如果你经常运行它。此外,它还集成在rebar3和erlang.mk。
如果您使用dialyzer( dia.erl),您将看到如下所示的结果。
Checking whether the PLT dia.plt is up-to-date... yes
Proceeding with analysis...
compile (+0.09s): 0.02s ( 1 modules)
clean (+0.00s): 0.00s
remote (+0.00s): 0.18s
order (+0.00s): 0.00s
typesig (+0.12s): 0.01s ( 3 SCCs)
order (+0.00s): 0.00s
refine (+0.00s): 0.01s ( 1 modules)
warning (+0.00s): 0.00s ( 1 modules)
(+ 0.71s)
dia.erl:5: Function bad/0 has no local return
dia.erl:5: The call lists:flatten(<<_:168>>) will never return since it differs in the
1st argument from the success typing arguments: ([any()])
done in 0m1.16s
done (warnings were emitted)
在这个例子下,dia.erl的第5行,我们使用 168 位长的二进制 ( <<_:168>>)对lists:flatten/1进行调用,而该函数需要一个列表 ( [any()]) 作为其参数。这个警告不是在编译时引发的,但是使用dialyzer你可以在它运行时发生错误之前找到它。
Erlang/OTP 发行版中包含的一个更简单的工具是xref. xref是一种交叉引用工具,可以分析您的代码并查找对不存在的函数、已弃用的函数和其他类似事物的调用。它不像dialyzer那样深入搜索,但它会立即发现明显的错误。
xref还与rebar3和erlang.mk(文档还没有,但它用xref_runner检查您的代码)集成。
xref可以找到如下错误
…
===> Running cross reference analysis...
===> Warning: your_module:your_function/1 calls undefined function this_function:doesnt_exist/1 (Xref)
…
xref检测到我们正在调用一个不存在于代码中的函数your_module:your_function/1。同样,这是编译器不会警告您的事情。
除了使用xref、dialyzer分析代码查找错误外,您还可以确保项目中的代码是可维护的。elvis是一个命令行工具(以及 Erlang 应用),您可以使用它来验证您的代码是否符合您在elvis.config文件中预先定义的某些样式规则。分别存在对应rebar3和erlang.mk的插件。 您还可以在线使用elvis来检查您的 github 拉取请求。
它的输出如下所示:
Loading files...
Loading src/dia.erl
Applying rules...
# src/dia.erl [FAIL]
- no_tabs
- Line 33 has a tab at column 0.
在这种情况下,elvis 正在检测用于缩进的制表符的使用,这是在项目elvis.config文件中指定为无效的内容。
下一组工具假设您已经创建了应用程序,将其打包为一个release,并将其部署到某个服务器。还假设该应用程序已经运行了一段时间,但已经开始出现异常行为。所以你需要调试它。
首先,您使用远程 shell连接到您的服务器(请参阅-remsh命令的链接)。然后,您使用 Erlang 的dbg。
唉,dbg不是一个非常直观、简单的调试工具。它真的很强大,但是手头的任务有更简单的工具。我将在下面向您展示其中的 2 个。
redbug是一个调试应用程序,它与dbg非常相似,但具有更直观的界面。它与eper一起提供,但老实说,redbug是eper中我唯一用过组件。您可以将跟踪模式指定为字符串,并且每次运行与该模式匹配的函数调用时,它将在控制台中打印一条消息。它看起来像这样:
1> redbug:start("your_module:your_private_function->return").
{156,1}
2> your_module:your_public_function().
% 19:55:12 <0.1.0>({erlang,apply,4})
% your_module:your_private_function(some, parameters)
% 19:55:12 <0.1.0>({erlang,apply,4})
% your_module:your_private_function/2 -> ok
ok
3>
我实际上倾向于在开始使用redbug时总是使用相同的选项。您可以使用redbug:help()检查可用的启动选项。因此,我已将此启动代码添加到我的user_default 中(不要在生产中这样做,孩子们!!)
redbug(What) ->
catch redbug:stop(),
timer:sleep(100),
redbug:start(What, [{time, 9999999}, {msgs, 9999999}, {print_msec, true}]).
现在我可以轻松上手redbug了。
4> redbug("your_module:your_private_function->return").
{156,1}
5> your_module:your_public_function().
% 19:59:13 <0.1.0>({erlang,apply,4})
% your_module:your_private_function(some, parameters)
% 19:59:13 <0.1.0>({erlang,apply,4})
% your_module:your_private_function/2 -> ok
ok
6>
但是跟踪函数调用只是检查 Erlang 服务器健康状况的众多方法之一。Fred Hebert在处理这个问题积累了大量经验,产出了一本很棒的书( Stuff Goes Bad: Erlang In Anger)和一个很棒的工具:recon。
使用recon你可以做很多事情,你可以:跟踪函数调用(就像redbug),恢复编译模块的源代码,检查应用程序内存消耗,计算消息队列长度,清理二进制内存,查找泄漏等等。我强烈建议您阅读这本书并尝试使用其中recon描述的不同工具。如果您的服务器开始出现异常行为,您将需要牢记它们。
现在有些并不真正适合上面的列表,但无论如何都值得一提。
如果你使用 TDD(即使你只是使用通用测试来测试你的 Erlang 应用程序并且你有兴趣使用我上面提到的工具来维护你的代码质量),你必须应用katana-test。使用下面的代码,你会在每次运行测试时都对代码进行dialyzer、xref和测试。
-module(your_meta_SUITE).
-include_lib("mixer/include/mixer.hrl").
-mixin([ktn_meta_SUITE]).
-export([init_per_suite/1]).
init_per_suite(Config) -> [{application, your_app} | Config].
我称之为Meta Testing,我已经写了两篇关于它的博客文章。在这里和这里查看它们。
如果不向背后的伟大开发者社区大声疾呼,任何关于Erlang的伟大的事物列表都是不完整的。如果您打算在 Erlang 上工作,或者即使您只是接触该语言并且想知道它的全部内容,那么您必须与 erlangers交流。
有几种方法可以做到这一点:
如果您对 Erlang 开发很认真,请密切关注这些平台并与我们保持联系以获取更新和其他机会!
最后,我想提一下 Inaka在 github 上发布的 Erlang 指南。正如我在第一次谈论它们时在邮件列表中所说的那样:
erlang_guidelines是我们(在 Inaka)在我们的 Erlang 代码中强制执行的一组标准。 …… 它只会反映在 Inaka 工作的〜8 erlangers 的想法。我们接受贡献,因为我们喜欢良好和建设性的辩论,但我们不希望任何人……喜欢我们的指导方针🙂
换句话说,关于那个 repo 的指导方针不需要成为你的指导方针,但你应该有自己的指导方针。fork那个 repo,然后根据你的想法调整它的内容可能是一个很好的开始方式。其他人已经这样做了。正如Iñaki曾经解释的那样:
代码格式、间距、布局和 “使代码看起来不错”并不是制定指南的目标。类似地,这个想法不是要参与其中每个人都被迫做他们不想做的事情的束缚计划,而是要有一个秩序和商定条款的基线。
达成共识并遵循它的目的是释放能量,而不是消耗它来支持定义不明确或主观的目标,例如“看起来更好”。让每个人制定他/她自己的规则“而该死的”就像强迫每个人遵守严格的指导方针一样反社会,这些指导方针规定了逗号或空格的放置位置。纪律为团队提供了自由,因为一旦你在一件事情上达成共识,处理他人过犯的努力比防止自己过犯的努力更大。
行长限制等问题是达到目的的一种手段:它们使代码更容易更改、调试和扩展,以更快地响应需求更改。要同意这一点,必须承认编程是一项社会活动,并且适用于群体行为。此时为您编写可能更容易,但其他人将不得不阅读它。这是代码指南的唯一目标。
希望本指南能够解决您可能遇到的有关基于 Erlang 的应用程序开发的一些问题,并激发您对创建 Erlang 应用程序的兴趣!感谢您的阅读。
今天,我们将看一个相当古老且有些古怪的东西。 你们大多数人可能没有注意到的语言。 虽然 Erlang 不像某些现代编程语言那样流行,但它安静地运行着 WhatsApp 和微信等每天为大量用户提供服务的应用程序。 在这篇文章中,我将告诉你关于这门语言的更多事情、它的历史,以及你是否应该考虑自己学习它。 ## 什么是 Erlang,它在哪里使用? Erl
Read More这篇文章探讨了 Erlang/OTP 25 中基于类型的新优化,其中编译器将类型信息嵌入到 BEAM 文件中,以帮助JIT(即时编译器)生成更好的代码。 ## 两全其美 OTP 22 中引入的基于SSA的编译器处理步骤进行了复杂的类型分析,允许进行更多优化和更好的生成代码。然而,Erlang 编译器可以做什么样的优化是有限制的,因为 BEAM 文件必须
Read More自从Erlang 存在,就一直有让它更快的需求和野心。这篇博文是一堂历史课,概述了主要的 Erlang 实现以及如何尝试提高 Erlang 的性能。 ## Prolog 解释器 Erlang 的第一个版本是在 1986 年在 Prolog 中实现的。那个版本的 Erlang 对于创建真正的应用程序来说太慢了,但它对于找出Erlang语言的哪些功能有用,哪
Read More