oracle / graalpython

A Python 3 implementation built on GraalVM
Other
1.2k stars 103 forks source link

java invoke python script cost too long in multi-threading #322

Closed rayduan closed 1 year ago

rayduan commented 1 year ago

hi,i want to implement java application invoke python script witih graalpython,but it cost too long, sigle eval cost 22256 ms here is my test code

   public static void main(String[] args) {
        try (Context context = Context.newBuilder("python").engine(engine).build()) {
            context.initialize("python");
        }
        long a = System.currentTimeMillis();
        final int MAX_CONCURRENT_TASKS = 100;
        final Semaphore SEMAPHORE = new Semaphore(MAX_CONCURRENT_TASKS);
        Context.Builder builder = Context.newBuilder("python").engine(engine);
        ExecutorService executor = Executors.newCachedThreadPool();
        for (int i = 0; i < 500; i++) {
            executor.submit(() -> {
                try {
                    SEMAPHORE.acquire();
                    getScriptResult(builder);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    SEMAPHORE.release();
                }
            });
        }
        executor.shutdown();
        while (true) {
            if (executor.isTerminated()) {
                break;
            }
        }
        long b = System.currentTimeMillis();
        System.out.println("cost:" + (b - a));
    }

    private static void getScriptResult(Context.Builder builder) throws InterruptedException, IOException {
        long start = System.currentTimeMillis();
        String script = "a+b";
        Source source = Source.newBuilder("python", script, "name").build();
        try (Context context = builder.build()) {
            Value objectObjectHashMap = context.getBindings("python");
            objectObjectHashMap.putMember("a", random.nextInt(100));
            objectObjectHashMap.putMember("b", 5);
            Value result = context.eval(source);
            System.out.println(result.asInt());
        }
        long end = System.currentTimeMillis();
        System.out.println("cost:" + (end - start));
    }

here is cost image

please tell me how to improve it

msimacek commented 1 year ago

Hi @rayduan, which version are you using? Can you try the latest snapshot build? I ran your example using the snapshot on my machine and it was much better:

cost:358
cost:369
cost:386
cost:388
cost:318
cost:400
cost:362
cost:430
cost:401
cost:393
cost:3711
rayduan commented 1 year ago

i'm use mac m1, graalvm jdk 11, and my sdk version is 22.3.1, i'm sure to init Context cost too many time ,but in multi-threading i can't reuse context

rayduan commented 1 year ago

also it's any way to sovle reuse Context bindings in multi-threading ? if i can resue context it work well ,but i need bindings diff params in every eval, i need your help please

msimacek commented 1 year ago

You can create a context per-thread and put it into a thread local variable.

i'm use mac m1

Did you download the macOS (aarch64) build of GraalVM? Don't use the macOS (amd64) build, that one is for Intel CPUs, it would work on the M1, but it would be slow.

rayduan commented 1 year ago

您可以为每个线程创建一个上下文并将其放入线程局部变量中。

我用的是mac m1

您是否下载了macOS (aarch64)GraalVM 的构建版本?不要使用macOS (amd64)该版本,它适用于 Intel CPU,它可以在 M1 上运行,但速度会很慢。

yes,i'm use amd64,i'll try to change it

rayduan commented 1 year ago

image yes,it work well,thank you very much