Scala loop-react's performance is so poor. What for?

I am just writing one demo of a consumer producer in scala and java. The demo shows that scala's performance is so poor. Is my code wrong?

Java AVG: 1933534.1171935236
Scala AVG: 103943.7312328648

Scala code:

import scala.actors.Actor.actor import scala.actors.Actor.loop import scala.actors.Actor.react import scala.concurrent.ops.spawn object EventScala { case class Event(index: Int) def test() { val consumer = actor { var count = 0l val start = System.currentTimeMillis() loop { react { case Event(c) => count += 1 case "End" => val end = System.currentTimeMillis() println("Scala AVG:" + count * 1000.0 / (end - start)) exit() } } } var running = true; for (i <- 0 to 1) { { spawn { while (running) { consumer ! Event(0) } consumer!"End" } } } Thread.sleep(5000) running = false } def main(args: Array[String]): Unit = { test } } 

Java Code:

 import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; public class EventJava { static BlockingQueue<Event> queue = new LinkedBlockingQueue<EventJava.Event>(); static volatile boolean running = true; static volatile Event sentinel = new Event(0); static class Event { final int index; public Event(int index) { this.index = index; } } static class Consumer implements Runnable { @Override public void run() { long count = 0; long start = System.currentTimeMillis(); while (true) { try { Event event = queue.take(); if (event == sentinel) { long end = System.currentTimeMillis(); System.out.println("Java AVG:" + count * 1000.0 / (end - start)); break; } count++; } catch (InterruptedException e) { } } } } static class Producer implements Runnable { @Override public void run() { while (running) { queue.add(new Event(1)); } queue.add(sentinel); } } static void test() throws InterruptedException { ExecutorService pool = Executors.newCachedThreadPool(); pool.submit(new Consumer()); pool.execute(new Producer()); pool.execute(new Producer()); Thread.sleep(5000); running = false; pool.shutdown(); } public static void main(String[] args) throws InterruptedException { test(); } } 
+4
source share
5 answers

You are testing two very different codes. Consider Java, for example:

  while (true) { 

Where is the opportunity for other "actors" to take the thread and do their own processing? This "actor" pretty much chases the thread. If you create 100,000 of them, you will see that the JVM will be crushed under the weight of competing "actors", or see how some of them get all the processing time, while others languish.

  Event event = queue.take(); if (event == sentinel) { 

Why do you pull the event out of the queue without checking if it can be processed or not? If it cannot be processed, you will lose the event. If you add it back to the queue, it will be completed after other events sent by the same source.

These are just two things that Scala code does, but Java doesn't.

+6
source

Overall, this is a very unscientific test. No workout. A small number of iterations. Very very uncomfortable. Look at the Google caliper or such ideas for creating the best micro-tests.

Once your numbers are clear: compile it in scala and then decompile in java. The answer may pop up.

I think in your case it could be the configuration of the actors. Try akka as well.

+4
source

I have a machine with 4 processors. If I run my Java code, I get full CPU utilization on a single processor (25%). That is, you are using one thread.

If I run scala code, I get full use of all processors, I get four threads.

So, I suspect that two things are happening: you get a count of the number of conflicts, and / or the count does not increase correctly.

Also, the test you run in the loop is a pattern match in Scala, but is a simple equality in Java, but I suspect this is a small part.

+3
source

Actors are intended for small messages that lead to meaningful calculations, and not for processing data on elements, as indicated above.

Your Actor’s code is really more comparable to a multi-thread ExecutorService, where each message is a new version of Runnable / Callable, and not what you have in your Java code.

Your test compares "how fast a worker thread can consume an item from the queue" and "how fast can scala send a message to the mailbox, notify and schedule the actor, and process the message." It is simply not the same, and it is not suitable for the same purpose.

Regardless, scala can also use Java threads. scala just gives you an extra (more secure, simpler and more communicative) concurrency mechanism.

+1
source

and respond to both exceptions for flow control purposes. This means that there are two tasks for the thread pool, only one of which does the actual work. Exceptions are also much more expensive than regular returns, even if the JVM successfully optimizes them to longjmps.

0
source

Source: https://habr.com/ru/post/1369152/


All Articles