gpt4 book ai didi

c - Erlang 产生大量 C 进程

转载 作者:太空狗 更新时间:2023-10-29 15:02:09 25 4
gpt4 key购买 nike

我一直在研究如何在 Erlang 中嵌入语言(让我们以 Lua 为例)。这当然不是一个新想法,有很多图书馆可以做到这一点。但是我想知道是否可以启动一个由 Lua 修改的状态的 Genserver。这意味着一旦你启动了 Genserver,它就会启动一个(长时间运行的)Lua 进程来操作 Genserver 的状态。我知道这也是可能的,但我想知道我是否可以产生 1,000、10,000 甚至 100,000 个这样的进程。

我不是很熟悉这个话题,但我做了一些研究。
(如果我对这些选项中的任何一个有错误,请纠正我)。

TLDR;跳到最后一段。

第一个选项:NIF:

这似乎不是一个选项,因为它会阻止当前进程的 Erlang 调度程序。如果我想生成大量这些,它将卡住整个运行时。

第二个选项:端口驱动程序:

它就像一个 NIF,但通过向指定端口发送数据来进行通信,该端口也可以将数据发送回 Erlang。这很好,尽管这似乎也阻止了调度程序。我试过一个库,它也为你做锅炉平台,但这似乎在产生 10 个进程后阻塞了调度程序。我还查看了 Erlang 文档中的 postgresql 示例,该示例据说是异步的,但我无法使示例代码正常工作(R13?)。甚至可以在不阻塞运行时运行尽可能多的端口驱动程序进程吗?

第三个选项:C 节点:

我认为这很有趣并想尝试一下,但显然“erlang-lua”项目已经这样做了。这很好,因为如果出现问题并且进程被隔离,它不会使您的 Erlang VM 崩溃。但是为了实际生成单个进程,您需要生成整个节点。我不知道这有多贵。我也不确定连接集群中节点的限制是什么,但我不认为自己会产生 100,000 个 C 节点。

第四个选项:端口:

起初我认为这与端口驱动程序相同,但实际上是不同的。您生成一个进程,该进程执行应用程序并通过 STDIN 和 STDOUT 进行通信。这对于生成大量进程很有效,而且(我认为?)它们不会对 Erlang VM 构成威胁。但是,如果我要通过 STDIN/STDOUT 进行通信,为什么还要费心使用可嵌入的语言呢?也可以使用任何其他脚本语言。

因此,在我不熟悉的领域进行了大量研究之后,我来到了这一点。您可以将 Genserver 作为“实体”,其中 AI 是用 Lua 编写的。这就是为什么我想为每个实体制定一个流程。我的问题是如何实现生成许多与长时间运行的 Lua 进程通信的 Genservers?这甚至可能吗?我应该以不同的方式解决我的问题吗?

最佳答案

如果你能让 Lua 代码——或者更准确地说,它的底层原生代码——与 Erlang VM 合作,你有几个选择。

考虑 Erlang VM 最重要的功能之一:管理(可能大量)Erlang 轻量级进程跨一组相对较小的调度程序线程的执行。它使用多种技术来了解进程何时用完其时间片或正在等待,因此应该安排它以让另一个进程有机会运行。

您似乎在问如何让 native 代码在 VM 中以它喜欢的方式运行,但是正如您已经暗示的那样, native 代码可能导致 VM 出现问题的原因是它没有实用的方法来停止 native 代码完全接管调度程序线程,从而阻止常规 Erlang 进程执行。因此, native 代码必须协同将调度程序线程交还给 VM。

对于较旧的 NIF,此类合作的选择是:

  • 将 NIF 调用在调度程序线程上运行的时间保持在 1 毫秒或更短。
  • 创建一个或多个私有(private)线程。将每个长时间运行的 NIF 调用从其调度程序线程转换为私有(private)线程执行,然后将调度程序线程返回给 VM。

  • 这里的问题是并非所有调用都可以在 1 毫秒或更短的时间内完成,并且管理私有(private)线程可能容易出错。为了解决第一个问题,一些开发人员会将工作分解成块,并使用 Erlang 函数作为包装器来管理一系列简短的 NIF 调用,每个调用完成一个工作块。至于第二个问题,嗯,有时你就是无法避免它,尽管它有其固有的困难。

    在 Erlang 17.3 或更高版本上运行的 NIF 也可以使用 enif_schedule_nif function 协作产生调度程序线程.要使用此功能, native 代码必须能够在块中完成其工作,以便每个块都可以在通常的 1 毫秒 NIF 执行窗口内完成,类似于前面提到的方法,但不需要人为地返回到 Erlang 包装器。我的 bitwise example code提供了许多有关此的详细信息。

    Erlang 17 还带来了一个实验性功能,默认关闭,称为脏调度程序。这是一组 VM 调度程序,与常规调度程序没有相同的 native 代码执行时间限制;在那里工作可以无限期地阻塞,而不会中断正常的 VM 操作。

    脏调度器有两种形式:用于 CPU 密集型工作的 CPU 调度器,以及用于 I/O 密集型工作的 I/O 调度器。在编译为启用脏调度程序的 VM 中,默认情况下,脏 CPU 调度程序的数量与常规调度程序的数量一样多,并且有 10 个 I/O 调度程序。可以使用命令行开关更改这些数字,但请注意,为了防止常规调度程序饥饿,您的 CPU 调度程序不能比常规调度程序更脏。应用程序使用相同 enif_schedule_nif前面提到的在脏调度程序上执行 NIF 的函数。我的 bitwise example code也提供了许多有关此的详细信息。脏调度器也将保留为 Erlang 18 的实验性功能。

    链接端口驱动程序中的 native 代码受制于与 NIF 相同的调度程序执行时间限制,但驱动程序具有 NIF 没有的两个功能:
  • 驱动程序代码可以将文件描述符注册到 VM 轮询子系统中,并在这些文件描述符中的任何一个变为 I/O 就绪时收到通知。
  • 驱动程序 API 支持访问非调度器异步线程池,其大小是可配置的,但默认情况下有 10 个线程。

  • 第一个功能允许 native 驱动程序代码避免阻塞 I/O 线程。例如,不是执行阻塞 recv调用,驱动程序代码可以注册套接字文件描述符,以便虚拟机可以轮询它并在文件描述符变得可读时调用驱动程序。

    第二个功能提供了一个单独的线程池,对于不能符合调度程序线程 native 代码执行时间限制的驱动程序任务很有用。您可以在 NIF 中实现相同的功能,但您必须设置自己的线程池并编写自己的 native 代码来管理和访问它。但是无论您是使用驱动程序异步线程池、您自己的 NIF 线程池还是脏调度程序,请注意它们都是常规的操作系统线程,因此尝试启动大量线程是不切实际的。

    native 驱动程序代码还没有脏调度程序访问权限,但这项工作正在进行中,它可能会在 18.x 版本中作为实验性功能提供。

    如果您的 Lua 代码可以利用这些功能中的一个或多个来与 Erlang VM 协作,那么您的尝试可能是可能的。

    关于c - Erlang 产生大量 C 进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30696094/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com