Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The performance of Scala's loop-react is so poor. Why?

I just write one producer-consumer demo in scala and java. The demo shows that the performance of Scala is so poor. Is my code wrong?

Java AVG:1933534.1171935236
Scala AVG:103943.7312328648

The 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
}

}

The 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();
}

}
like image 923
liutao Avatar asked Dec 09 '22 06:12

liutao


1 Answers

You are testing two very different codes. Let's consider Java, for instance:

    while (true) {

Where's the opportunity for the other "actors" to take over the thread and do some processing of their own? This "actor" is pretty much hogging the thread. If you create 100000 of them, you'll see JVM get crushed under the weight of the competing "actors", or see some get all processing time while others languish.

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

Why are you taking the event out of the queue without checking if it can be processed or not? If it couldn't be processed, you'll loose the event. If you added it back to the queue, it will end up after other events sent by the same source.

These are just two things that the Scala code does and the Java one doesn't.

like image 140
Daniel C. Sobral Avatar answered Dec 21 '22 23:12

Daniel C. Sobral