安排固定延迟执行器时防止 R 脚本完成

Prevent R script from finishing when scheduling fixed delay executor

我计划使用 FastR 实现编写一个 R 脚本,看起来像

    java.addToClasspath("build/libs/polyglot-example-f.jar")
    clientClass <- java.type('org.algo.polyglot.JavaClient')
    javaClient <- new(clientClass, threadPoolSize=10)
    javaClient$startScheduleWithFixedDelay(5)

org.algo.polyglot.JavaClientclass的样子(打包成jar):

    package org.algo.polyglot;

    import org.apache.commons.lang3.RandomStringUtils;
    import org.apache.commons.lang3.RandomUtils;
    import org.graalvm.polyglot.HostAccess;

    import java.text.MessageFormat;
    import java.util.concurrent.Executor;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;

    import org.graalvm.polyglot.HostAccess.Export;

    public class JavaClient {

        private final ScheduledExecutorService service;

        @Export
        public JavaClient(int threadPoolSize) {
            this.service = Executors.newScheduledThreadPool(threadPoolSize);
        }

        @Export
        public void startScheduleWithFixedDelay(int delayInSeconds) {
            service.scheduleWithFixedDelay(
                    () -> {
                        postMessage(fetchMessage());
                    },
                    0,
                    delayInSeconds,
                    TimeUnit.SECONDS
            );
        }

        @Export
        public void startScheduleWithFixedRate(int period) {
            service.scheduleAtFixedRate(
                    () -> {},
                    0,
                    period,
                    TimeUnit.SECONDS
            );
        }

        @Export
        public PolyglotMessage fetchMessage() {
            return new PolyglotMessage(
                    RandomStringUtils.randomAlphabetic(10, 15),
                    RandomStringUtils.randomAlphabetic(10, 15),
                    System.currentTimeMillis()
            );
        }

        @Export
        public void postMessage(PolyglotMessage message) {
            System.out.println("[Printed from JavaClient] Posting message: " + message.toString());
        }
    }

当 运行 将脚本与 Rscript sample.R --polyglot 连接时,脚本完成执行并输出:

    $ Rscript sample.R --polyglot
    NULL

我有这些动机:

    future <- javaClient$startScheduleWithFixedDelay(5)
    future$get()
    @Export
    public ScheduledFuture<?> startScheduleWithFixedDelay(int delayInSeconds) {
        return service.scheduleWithFixedDelay(
                () -> {
                    postMessage(fetchMessage());
                },
                0,
                delayInSeconds,
                TimeUnit.SECONDS
        );
    }

    myFunc <- function() {
        # do some stuff
    }

javaClient$runProvidedFunction(myFunc)

    @Export
    public void runProvidedFunction(Runnable runnable) {
        runnable.run();
    }

但是不同线程的访问受到限制

我想知道这些动机是否可能,如果可能,正确的方法。

Run the R script with the provided jar

看来是你自己想出来的。您可以使用 java.addToClasspath 或在 --vm.cp=... 开始 R/Rscript 时应该能够添加到 class 路径。这两个选项仅在 JVM 模式下有效。

Execute the script with Rscript

再说一遍,你好像明白了?

Pass a function to the executor from the R script so that the function is called accordingly by the ScheduledExecutorService

这很棘手。 R 是单线程语言,FastR 也是。您不能从多个线程执行 R 代码,但您可以做的是创建多个 FastR 上下文并在每个线程中使用一个新上下文(您可以为此使用 ThreadLocal)。参见 https://www.graalvm.org/reference-manual/embed-languages。您应该能够使用从 R 调用的 Java 代码中的上下文 API 并创建新的上下文。

Build a native image with the runnable script and jar

应该没问题。请注意,某些 R 包和本机映像存在一些我们尚未修复的已知问题。

入口点必须是某个 Java 使用上下文 API 启动 FastR 的应用程序。您可以将 R 脚本作为字符串或资源嵌入到 Java 应用程序中。请注意,不会提前编译 R 代码。它仍将在运行时进行 JIT 编译,但其他所有内容都将提前编译:您的 Java 代码、您使用的任何 Java 库、FastR 解释器和运行时。