【问题标题】:Erlang style concurrency in the D programming languageD 编程语言中的 Erlang 风格并发
【发布时间】:2011-04-30 00:54:54
【问题描述】:

我认为 Erlang 风格的并发是核心数量呈指数增长的答案。你可以用其他主流语言来伪造它。但解决方案总是让我想要。我不愿意放弃多范式编程(C++/D)转而使用 Erlang 严苛的语法。

什么是 Erlang 风格的并发:

来自一位语言作者(What is Erlang's concurrency model actually ?):

  • 轻量级并发。
    创建线程成本低,维护疯狂数字成本低。
  • 异步通信。
    线程仅通过消息进行通信。
  • 错误处理。
  • 进程隔离。

或来自知情博主 (What is Erlang-Style Concurrency?):

  • 快速创建/销毁进程
  • 能够支持 >> 10 000 个并发进程,但特性基本保持不变。
  • 快速异步消息传递。
  • 复制消息传递语义(无共享并发)。
  • 过程监控。
  • 选择性消息接收。

我认为D's message passing 可以完成大部分这些功能。我想知道的是“>>10,000 个并发进程(线程)”和“快速进程创建/销毁”。

D 处理这些要求的能力如何?

我认为要正确支持它们,您必须使用green threads。 D的消息传递特性可以和绿色线程库一起使用吗?

【问题讨论】:

  • 在 Rust 中。 Rust 具有消息传递、模式匹配和绿色线程,允许大量并发任务/进程。它也有一些类型的通道(类似于 Go)。

标签: concurrency erlang d


【解决方案1】:

默认情况下,存储在 D 中是线程本地的,因此除非特别标记为 shared,否则线程之间不会共享任何内容。如果将变量标记为shared,则可以使用传统的互斥锁和条件以及同步对象等来处理并发。但是,线程之间通信的首选方式是使用 std.concurrency 中的消息传递工具,并让所有数据保持线程本地,仅在必须时使用shared。使用 std.concurrency 在线程之间传递的所有对象都必须按值传递或者是不可变的,因此那里不会发生共享并且它是完全线程安全的。但是,目前获得一个不是数组的不可变引用类型可能会有点痛苦(idup 通常使数组更容易),因此传递值类型以外的任何内容可能会有点烦人或数组(尽管希望这种情况会随着与 const 和 immutable 相关的编译器和标准库错误得到修复并且更多代码是 const 正确的)尽快改善。

现在,虽然 D 中的消息传递肯定会产生比 C++ 或 Java 等语言更干净、更安全的代码,但它构建在普通 C 线程之上(例如Linux 使用 pthreads),因此它没有 Erlang 那样的轻量级线程,因此处理多线程不会像 Erlang 那样高效。

当然,我看不出有什么理由不能使用 D 编写更高效的线程系统,此时您可能能够获得与 Erlang 相似的线程效率,并且它可能使用 API与 std.concurrency 类似,但 D 的所有标准线程都是建立在普通 C 线程之上的,因此您必须自己完成所有这些工作,具体取决于您如何实现它以及取决于thread-local/shared 的东西由编译器和运行时处理,很难让类型系统强制所有东西都是线程本地的,你的“绿色”线程。恐怕我对 shared 的具体实现方式或“绿色”线程的工作方式了解不够。

不管怎样,D 的消息传递系统肯定会导致处理线程比 C++ 甚至 Java 更愉快,但它的设计并不是像 Erlang 那样精简。 D 是一种通用系统语言,而不是专门设计用于一切使用线程并因此尽可能有效地使用它们的语言。 D 的大部分标准设施都是建立在 C 之上的,因此它的很多效率特性将与 C 相似。

【讨论】:

  • Erlang 线程实际上只是一个堆栈框架和一些上下文 - 可能 Fiber 是一个更贴切的术语。 Erlang 虚拟机调度了几个操作系统线程来为 1000 条用户模式光纤提供服务。这比任何其他方案都简洁且可扩展,但使 D 的共享与线程本地存储的概念变得毫无用处。这不是 D 的错,因为至少 x86 处理器没有提供硬件强制措施来将一根光纤数据与另一根光纤数据隔离开来。例如,对于真正的 OS 线程,x86 GS 寄存器在 64 位机器中保持每个线程的数据隔离。
  • 此外,如果您不担心线程本地存储问题,D 确实有一个可以很好地工作的光纤库。 D 纤维之间的上下文切换时间大约是 D 线程之间的 6 倍。
  • D Fibers 包含在标准库中。但它们只实现了非抢占式多任务处理。
  • @srking Erlang 的“纤维”类线程的巧妙之处在于它们被有效地抢先调度(不像 Go、Node 等中等效的绿色线程/协程)
【解决方案2】:

此功能经常与异步 I/O 结合使用,以有效地与外部数据源进行通信。 vibe.d 框架似乎提供了 many-fibers-on-a-few-OS-threads 线程模型和异步 I/O 库(除了一大堆 Web 应用程序库和项目管理工具)。

作为一个不相关的旁注,D 既足够低级,您可以在其中编写这个框架,又足够高级,可以成为一种引人注目的语言,可以在框架之上编写您的 Web 应用程序,这真是太酷了.其他具有类似框架的流行语言(node.js、Ruby 的 EventMachine、Python 和 Go 中的协程)在低级系统编码方面无法与 D 竞争。其他具有类似系统编程工具的流行语言(C、C++)无法与高级应用程序编码竞争。

我是 D 的新手,但我得说,我喜欢我所看到的。

【讨论】:

    【解决方案3】:

    根据我对 D 的了解:它的消息传递基础设施是建立在它的线程设施之上的。如果核心线程库是 OS 线程的包装器,那么 D 中的并发性几乎不可能达到 Erlang 的量级(>> 10000)。此外 D 不强制对象的不变性,所以很容易把事情搞砸。所以,Erlang 是重并发的最佳选择。也许你可以在 Erlang 中编写并发的东西,在 D 中编写项目的其余部分。尽管如此,在 C 语言(C++、D 等)中仍然可以有高效的绿色线程——看看ProtothreadsZeroMQ .您可以使用这些实现非常高效的消息传递框架,并通过 C shim 或 directly from D 调用它们。

    【讨论】:

    • 可以使用 immutable 修饰符使 D 中的对象(深)不可变。这不是默认设置。
    • @KennyTM 是的,这就是为什么我说“D 不要强制对象的不变性......”
    • @Vijay:是的,是吗?您不能通过 D 的消息传递接口发送可变数据。如果您发送的对象不是immutable,编译器会阻止您。
    • @Vijay:可变全局变量默认为“线程本地”。可以通过添加 shared 修饰符使其共享(参考:digitalmars.com/d/2.0/migrate-to-shared.html.
    • 简而言之,D 不会阻止线程敌对特性的使用(它毕竟具有内联 ASM 和对 C 的直接访问),但它会让你在使用它们时有点不习惯. (这是 D 设计理念的重要组成部分。)
    猜你喜欢
    • 2010-09-06
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 2010-11-15
    • 1970-01-01
    • 2021-05-26
    • 2014-11-07
    • 1970-01-01
    相关资源
    最近更新 更多