9

我最近读到了Quasar,它为 JVM 提供了“轻量级”/类似 Go 的“用户模式”线程(它也有一个受 Erlang 启发的 Actor 系统,比如 Akka,但这不是主要问题)

例如:

package jmodern;

import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.strands.Strand;
import co.paralleluniverse.strands.channels.Channel;
import co.paralleluniverse.strands.channels.Channels;

public class Main {
    public static void main(String[] args) throws Exception {
        final Channel<Integer> ch = Channels.newChannel(0);

        new Fiber<Void>(() -> {
            for (int i = 0; i < 10; i++) {
                Strand.sleep(100);
                ch.send(i);
            }
            ch.close();
        }).start();

        new Fiber<Void>(() -> {
            Integer x;
            while((x = ch.receive()) != null)
                System.out.println("--> " + x);
        }).start().join(); // join waits for this fiber to finish
    }
}

据我了解,上面的代码不会产生任何 JVM / 内核线程,所有这些都是在用户模式线程中完成的(或者他们声称),这应该更便宜(如果我理解正确的话,就像 Go 协程一样)

我的问题是 - 据我了解,在 Akka 中,一切仍然基于 JVM 线程,大多数情况下映射到本机 OS 内核线程(例如 POSIX 系统中的 pthreads),例如据我所知有没有用户模式线程/像 Akka 中的协同程序/轻量级线程一样,我理解正确吗?

如果是这样,那么您知道这是否是一种设计选择吗?或者未来在 Akka 中是否有类似 go 的轻量级线程的计划?

我的理解是,如果你有一百万个 Actor,但其中大多数是阻塞的,那么 Akka 可以用更少的物理线程来处理它,但是如果它们中的大多数是非阻塞的,你仍然需要系统的一些响应(例如服务百万个小请求流式传输一些数据)然后我可以看到用户模式线程实现的好处,它可以允许更多的“线程”以较低的创建切换和终止的成本存活(当然唯一的好处是平均分配响应许多客户,但响应能力仍然很重要)

我的理解或多或少是正确的?如果我错了,请纠正我。

*我可能完全将用户模式线程与 go/co-routines 和轻量级线程混淆了,上面的问题依赖于我对它们都是相同的理解不足。

4

2 回答 2

9

Akka 是一个非常灵活的库,它允许您使用(本质上归结为通过一系列特征归结为)一个简单的 trait 来调度 Actor ExecutionContext,正如您所见,它接受Runnables 并以某种方式执行它们。因此,据我所知,很可能可以编写与 Quasar 之类的绑定并将其用作 Akka 演员的“后端”。

然而,Quasar 和类似的库可能会为光纤之间的通信提供特殊的实用程序。我也不知道他们将如何处理像 I/O 这样的阻塞任务,可能他们也会有这样的机制。因此,我不确定 Akka 是否能够在绿色线程上正确运行。Quasar 似乎也依赖于字节码检测,这是一种相当先进的技术,可能会产生很多影响,阻止它支持 Akka。

但是,在使用 Akka Actor 时,您不应该真正担心线程的轻量性。事实上,Akka 完全能够在单个系统上创建数百万个 Actor(请参阅此处),并且所有这些 Actor 都可以正常工作。

这是通过对特殊类型的线程池(如 fork-join 线程池)进行巧妙调度来实现的。这意味着除非actor在一些长时间运行的计算上被阻塞,否则它们可以运行的线程数量明显少于这些actor的数量。例如,您可以创建一个最多使用 8 个线程的线程池(8 核处理器的每个内核一个),并且所有参与者活动都将在这些线程上调度。

如果需要,Akka 灵活性允许您配置精确的调度程序以用于特定的参与者。您可以为长期运行的任务(如数据库访问)中的参与者创建专用调度程序。请参阅此处了解更多信息。

所以,简而言之,不,你不需要演员的用户态线程,因为演员不会一对一地映射到本机线程(除非你强迫他们这样做,但应该不惜一切代价避免这种情况) .

于 2014-05-01T20:40:39.213 回答
3

Akka Actor 本质上是异步的,这就是为什么你可以拥有很多 Actor,而 Quasar Actor(是的,Quasar 也提供 Actor 实现)非常接近 Erlang,是同步阻塞的,但它们使用 Fiber 而不是 Java(即目前的 OS) 线程,因此您仍然可以拥有许多具有与异步相同的性能但编程风格与使用常规线程和阻塞调用时一样简单的编程风格。

I/O 通过集成处理:Quasar 包含一个框架,可将异步和同步 API 转换为光纤阻塞,而Comsat已经包含许多此类集成(一个带有 Java NIO 的集成直接包含在 Quasar 中)。

我对另一个问题的回复包含更多信息。

于 2015-10-25T10:38:54.207 回答