Erlang/OTP 23亮点

2020-05-13 23:10:16

OTP 23刚刚发布(2020年5月13日),在最终发布之前,我们经历了一个漫长的过程,分别在2月、3月和4月发布了三个版本。我们非常感谢我们得到的关于发布候选版本的反馈,这些反馈揭示了我们内部测试没有发现的一些错误和缺陷。

您可以在此处下载描述更改的自述文件:OTP 23自述文件。或者,像往常一样,查看您感兴趣的应用程序的发行说明。例如:此处的实例:OTP 23 ERTS发行说明。

在OTP23中,我们在语言和编译器中添加了一些新特性,其中一个自从引入位语法以来一直处于积压状态,另一个则是来自社区的建议。

在二进制匹配中,现在允许要匹配的段的大小是保护表达式。在下面的示例中,变量SIZE被绑定到前8位,然后在表达式(SIZE-1)*8中用于后面的二进制文件的大小。

在当前的映射匹配语法中,映射模式中的键必须是单个值或文字。如果地图中的键是复杂术语,这会导致不自然的代码。​。

使用OTP23,映射匹配中的键可以是保护表达式,如您在new_example2.​中所见。

唯一的限制是键表达式中使用的所有变量必须事先绑定。

下面的非法示例显示仍然不支持使用未绑定变量作为键模式表达式的一部分。在这种情况下,键没有绑定,并且要求键表达式中使用的所有变量必须事先绑定。

出于可读性的目的,现在允许在数字之间写下划线的数字文字。但是下划线的位置并不是完全自由的,有一些规则。请参阅下面的允许使用示例:

在下面的示例中,我们有一些不允许放置下划线的示例:

派生操作在可伸缩性和分布式情况下的性能方面得到了改进。也就是说,当在另一个节点上派生进程时。

还添加了新功能,例如分布式SPOWN_MONITOR()BIF。此函数创建新进程并自动设置监视器。

spawn_opt()BIF还将支持MONITOR选项,用于在另一个节点上创建进程时自动设置监视器。

我们还添加了新的SPOWN_REQUEST()BIF,用于异步派生进程。SPOWN_REQUEST()支持SPOWN_OPT()已经支持的所有选项。

上面描述的派生改进还可以用于优化和改进RPC模块中的许多功能,但是由于新功能不是100%兼容的,我们决定引入一个名为ERPC的新模块,并将保留旧的RPC模块。

ERPC模块实现由RPC模块提供的操作的增强子集。

增强的意义在于它可以区分返回值、引发的异常和其他错误。​。

与原始的RPC实现相比,ERPC还具有更好的性能和可伸缩性。这是通过利用新引入的SPOWN_REQUEST()BIF实现的。

rpcmodule现在与ERPC共享相同实现,RPC的用户将自动受益于ERPC中的性能和可伸缩性改进。

下面的图片说明了rpc:call()的旧实现和新实现,并说明了为什么新实现更高效、更具伸缩性。

正如您在上面的“旧”实现中看到的那样,rpc:call依赖于接收节点上的rex进程来产生一个临时进程来执行被调用的函数。如果有许多并发的rpc:调用指向该节点,这将使rex成为瓶颈。

新的解决方案根本不使用rex,并让衍生的进程对调用的参数进行解码,从而避免了在“旧”实现中发生的一些不必要的数据复制。

在OTP 22中,我们引入了新的实验性套接字API。此API背后的想法是拥有一个稳定的中间API,可用于创建不属于更高级别的gen_*API的功能。

现在,我们在替换inet驱动程序的计划中又前进了一步,可以将gen_tcp API与套接字一起用作可选的后端。

为了便于使用gen_tcp使用现有代码进行测试,可以使用一个新选项{inet_backend,socket|inet}来选择套接字实现,而不是默认的inet实现。此选项必须首先放在选项列表中的函数:GEN_TCP:LISTEN、GEN_TCP:CONNECT和GEN_TCP:fdopen中,这些都是创建套接字的函数。例如,如下所示:

返回的套接字是标记为3元组的';$inet';而不是端口,因此所有其他API函数都将为套接字使用正确的实现。

更一般的覆盖是使用内核配置变量NETBACKEND,并将其设置为Socket或inet。例如,在erl命令行上,

我们已经实现了EEP 48,它指定了BEAM语言要使用的API文档的存储格式。通过标准化API文档的存储方式,可以编写跨语言工作的工具。

通过为所有OTP模块生成.chunk文件来扩展普通文档构建。您可以运行make docs DOC_TARGETS=CHUNKS来仅构建EEP 48个块。只运行make docs而不设置DOC_TARGETS变量将构建所有格式(html、man、pdf、chunks)。

在这些新功能的基础上,我们在shell中添加了具有以下功能的联机帮助:

还有相应的函数ht/1,2,3和hcb/1,2,3来获取有关类型和回调函数的帮助。

我们在stdlib中添加了一个新的模块shell_docs,该模块具有为shell呈现文档的函数。例如,这可以由开发环境使用,例如那些基于语言服务器协议(LSP)的开发环境。

代码模块还获得了一个新函数get_doc,该函数在不加载模块的情况下返回文档块。

4>;h(列表,排序,2)。-SPEC SORT(FUN,List1)->;List2 When Fun::Fun((A::T,B::t)->;Boolean()),List1::[t],List2::[t],T::Term()。根据排序函数FUN返回包含清单1的已排序元素的列表。Fun(A,B)是如果A在排序中比较小于或等于B,则返回TRUE,否则返回FALSE。OK。

壳体中的制表符补全也得到了改进。以前,模块的制表符补全只适用于已经加载的模块,现在扩展到适用于代码路径中所有可用的模块。补全还扩展到在“help”函数h、ht和hcb内工作。例如,您可以按Tab键,如下例所示,并获得以l开头的所有模块:

5>;h(llcnt leex列出LOCAL_TCP LOCAL_UDP LOGER_MF_h LOGER LOGER_BACKEND LOGER_CONFIG LOGER_DISK_LOG_h LOGER_Filters LOGER_Formatter LOGER_h_COMMON LOGER_HANDLER_WATCHER LOGER_OLP LOGER_PROXY LOGER_SERVER LOGGER_SIMPLE_H LOGER_STD_H LOGER_SUP。

现在,在决定在线计划程序的默认数量时,会考虑CPU配额。

因此,自动使Erlang成为应用了配额的容器环境中的好公民,比如带有--cpu标志的docker。

在基于云和容器的环境中,运行分布式Erlang节点而不使用EPMD并使用硬编码端口或替代服务发现可能很有趣。正因为如此,我们介绍了一些方法,以便在没有EPMD的情况下更轻松地启动和配置系统。

我们在Erlang分布协议中改进了连接建立过程中的握手,现在可以在不依赖EPMD或其他对等节点版本的先验知识的情况下就协议版本达成一致。

与新握手一起引入的另一个特性是动态节点名称。使用选项-name name或-sname name选择动态节点名称,并将name设置为unfined。

这些选项使Erlang运行时系统成为分布式节点。这些标志调用节点变为分布式所需的所有网络服务器;请参见net_kernel。还可以确保在启动Erlang之前在当前主机上运行EPMD;请参见EPMD和-start_epmd选项。

OTP 23中的新功能是可以将名称设置为未定义,然后节点将以优化为另一个节点的临时客户端的特殊模式启动。启用后,节点将从其连接的第一个节点请求动态节点名称。此外,还将隐含以下分发设置:

因为-dist_auto_connect设置为Never,系统必须手动调用net_kernel:connect_node/1才能开始分发。如果分发通道关闭,当节点使用动态节点名时,该节点将停止分发,并且必须重新调用net_kernel:connect_node/1。请注意,如果删除分发,然后重新设置,则节点名称可能会更改。

注意!OTP 23支持动态节点名称功能。临时客户端节点和第一个连接的对等节点(提供动态节点名)都必须至少是OTP 23才能工作。

为了让用户更好地控制EPMD的使用,向inet发行版添加了一些新选项。

-dist_listen false设置分发通道,但不侦听传入连接。当您希望使用当前节点与同一台计算机上的另一个节点交互而不加入整个群集时,这很有用。

-ERL_EPMD_PORT端口配置内置EPMD客户端应返回的默认端口。这允许本地节点知道群集中的任何其他节点要连接到的端口。

-remsh Node使用连接到Node的远程shell启动Erlang。如果没有给定-name或-sname,则将使用-sname unfinded启动节点。如果节点使用长名称,则应提供未定义的名称。如果节点不包含主机名,则会自动从-name或-sname选项中获取主机名。

注在OTP-23之前,用户需要提供有效的-sname或-name才能使用-remsh。如果目标节点未运行OTP-23或更高版本,情况仍然如此。

#Starting the E-node testerl-Sname test@localhost#启动一个临时E节点(使用动态名称)作为远程shell到#节点testerl-remsh test@localhost。

erl_epmd回调API也已扩展,允许返回-1作为创建,这意味着节点将创建随机创建。

此外,还添加了一个名为LISTEN_PORT_PUEST的新回调函数,该函数允许回调返回分发版应该使用哪个侦听端口。如果要从外部服务获取侦听端口,则可以使用它来代替inet_dist_listen_min/max。

erl_call是一个C程序,最初作为示例捆绑在erl_interface应用程序中。ERL_INTERFACE包含用于与Erlang节点通信的C库,并让C程序的行为就像它们是Erlang节点一样。然后它们被称为C节点。ERL_CALL已经变得流行起来,并且在产品中主要用于管理同一主机上的Erlang节点。在OTP23中,erl_call安装在与erl相同的路径下,使其在该路径中可用,而无需担心erl_interface版本。erl_call中的另一个新功能是地址选项,该选项可用于直接连接到节点,而不需要依赖EPMD来解析节点名称。

AFAIK erl_call在即将到来的RELX版本(由rebar3使用)中用于node_tool函数。

现在支持TLS-1.3(在OTP22中,我们将其归类为试验性的),但功能还不完整。支持的主要功能包括:

尚不支持“早期数据”功能。早期数据是TLS 1.3中引入的优化,它允许客户端在连接的第一个往返行程中将数据发送到服务器,而无需等待TLS握手完成(如果客户端最近与同一服务器通话)。

在OTP 23中,默认情况下,客户端和服务器都将TLS 1.3宣布为首选协议版本。没有显式配置TLS版本的用户应该意识到这一点,因为这可能会影响互操作性。

为ssl:cipher_suites/2,3提供了一个新选项EXCLUSIVE,并且扩展了ssl:versions,以更好地反映当前Erlang/OTP设置可用的TLS版本。

开放源码用户的Pull请求提供了两个值得注意的SSH特性,即支持从ssh代理获取密钥和TCP/IP端口转发。端口转发有时称为隧道或TCP转发/直接TCP。在OpenSSH客户端中,端口转发对应于选项-L和-R。

SSH代理存储的密钥提高了安全性,而端口转发通常用于获得两台主机之间的加密隧道。在密钥处理方面,使用OpenSSH文件格式“openssh-key-v1”重写并扩展了默认密钥插件ssh_file.erl。到目前为止,一个限制是新格式的密钥不能加密,默认插件现在也使用端口号,这增加了安全性。

现在可以在Erlang配置文件中配置SSH应用程序。这提供了例如在不改变代码的情况下改变所支持的算法集的可能性。

OTP-22.0中引入了一种新的加密API。使用新API的主要原因是使用支持硬件加速的OpenSSL libcrypto EVP API(如果机器支持的话)。密码算法的命名也是系统化的,现在遵循OpenSSL中的模式。

Crypto应用程序的一些部分使用非常旧的API,而其他部分使用的是最新的API。事实证明,以新的方式使用旧的API,并仍然保持向后兼容,是不可能的。

因此,旧的API暂时保留,但使用新的原语实现。旧的API在OTP-23.0中已弃用,将在OTP-24.0中删除。