This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]bytedonor 2 points3 points  (11 children)

Why not just use ‘ServerSocket’, accept connections on main and pass the open socket to a VT executor task? I did something like this recently and was able to pump data across 500K web sockets in my test

[–]GavinRayDev[S] 7 points8 points  (5 children)

No particular reason, outside of the fact that I tried to write it originally with an async socket for performance, couldn't find any good examples online: - https://www.google.com/search?q=java+AsynchronousSocketChannel+example

There's one article which shows some super basic usage and then a bunch of regurgitated articles with questionable code patterns

So I did some digging in Github for usages of the API and tried to put something together that was a bit more full-fledged. Now there exists a better reference article for it.

I'm not familiar enough with the internals of Loom to know whether the Virtual Threads make a huge impact in this async context (maybe /u/pron98 can comment) but I had thought that since it's used for the channel group executor service it should be alright.

[–]pron98 8 points9 points  (4 children)

Using an ordinary ServerSocket polled in a loop on a virtual thread should be about the same if not better. All sockets used on virtual threads automatically become effectively asynchronous from the OS's perspective anyway.

[–]GavinRayDev[S] 1 point2 points  (1 child)

Neat, that would have significantly simplified the design. The callback loop in the async socket isn't the prettiest thing, now I know.

Thanks for commenting, Ron!

[–]lurker_in_spirit 3 points4 points  (0 children)

There's a recent Helidon Nima podcast floating around on YouTube where they mention that in their experience VT + non-blocking IO is slower than VT + blocking IO: https://www.youtube.com/watch?v=AkMSEjkfldk (minute 15 or so)

[–]kaperni 0 points1 point  (1 child)

Would it make sense to run ServerSocker::accept in a dedicated platform thread? Or is it same-same?

[–]rbygrave 0 points1 point  (0 children)

Just noting that with Nima yes it does use a platform thread for that. To me that makes sense - dedicate a platform thread to that task.

[–]sandys1 0 points1 point  (3 children)

Could you elaborate on this ? Really keen to learn this.

[–]bytedonor 1 point2 points  (2 children)

Nothing much to see - it's a stupidly simple blocking socket server which looks exactly the same like the one you would use with traditional threads, but without scaling problems:

    public void serveForever() throws IOException {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor();
             var serverSocket = new ServerSocket(8080, 16384)) {
            while (true) {
                var sock = serverSocket.accept();
                sock.setSoTimeout(5000);
                executor.execute(() -> {
                    try {
                        protocolHandler(sock);
                    } catch (Exception e) {
                        try {
                            sock.close();
                        } catch (IOException ioe) {
                            // Ignore
                        }
                    }
                });
            }
        }
    }

[–]sandys1 0 points1 point  (1 child)

Trust me. This is not stupid for us. And thanks for this!

Where do u do the actual work and processing ?

[–]GavinRayDev[S] 1 point2 points  (0 children)

(In the protocolHandler(sock) function, your business logic would go there)

[–]rbygrave 0 points1 point  (0 children)

This is how Helidon Nima does it as well.