使用Akka框架的参与者之间的Java意外同步行为

使用Akka框架的参与者之间的Java意外同步行为,java,synchronization,locking,akka,pi,Java,Synchronization,Locking,Akka,Pi,我最近学习了Java中的Akka框架。当我练习初学者教程时,我遇到了一个有趣的同步问题 基本上,我的代码使用两个主机以相同的精度计算Pi两次。不同的是,一位大师将产生几个Akka演员来并行计算Pi,而另一位大师将以传统的顺序方式计算Pi。这是为了比较性能 package Citi.CAG.MIFID.AkkaTry; import Citi.CAG.MIFID.Common.AppConfig.AppConfig; import Citi.CAG.MIFID.Common.Log.Loggin

我最近学习了Java中的Akka框架。当我练习初学者教程时,我遇到了一个有趣的同步问题

基本上,我的代码使用两个主机以相同的精度计算Pi两次。不同的是,一位大师将产生几个Akka演员来并行计算Pi,而另一位大师将以传统的顺序方式计算Pi。这是为了比较性能

package Citi.CAG.MIFID.AkkaTry;

import Citi.CAG.MIFID.Common.AppConfig.AppConfig;
import Citi.CAG.MIFID.Common.Log.LoggingHandler;
import akka.actor.*;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import akka.japi.Creator;
import akka.japi.pf.ReceiveBuilder;
import akka.routing.ActorRefRoutee;
import akka.routing.RoundRobinRoutingLogic;
import akka.routing.Routee;
import akka.routing.Router;
import com.typesafe.config.ConfigFactory;
import sun.rmi.runtime.Log;

import java.time.Duration;
import java.util.LinkedList;
import java.util.function.Consumer;
import java.util.stream.IntStream;

public class Pi {

private static class Calculator {
    private final int index;
    private final int trunkSize;
    private double result = 0;
    private boolean isCalculated = false;
    public Calculator(int index, int size) {
        this.index = index;
        trunkSize = size;
    }

    public int getIndex() {
        return index;
    }

    public int getTrunkSize() {
        return trunkSize;
    }

    public void calculate() {
        for(int i = index * trunkSize; i < (index + 1) * trunkSize; ++i) {
            result += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1);
        }
        isCalculated = true;
    }
}

private static class Slave extends AbstractActor  {

    private double calculatePiFor(int start, int nrOfElements) {
        double acc = 0.0;
        for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) {
            acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1);
        }
        return acc;
    }
    Slave() {
        receive(ReceiveBuilder.match(Calculator.class, msg -> {
            //msg.result = calculatePiFor(msg.getIndex(), msg.getTrunkSize());
            //msg.isCalculated = true;
            msg.calculate();
            sender().tell(msg, self());
        }).build());
    }

    static Props props() {
        return Props.create(Slave.class, Slave::new);
    }
}

private static class Master extends AbstractActor {

    private int resultCount = 0;
    private double result = 0.0d;
    private final long startTime = System.currentTimeMillis();
    private final ActorRef listener;
    private final Router router;

    public Master(ActorRef listener, int workerCount, int trunkCount, int trunkSize) {
        LinkedList<Routee> actorRefs = new LinkedList<>();
        for(int i = 0 ; i < workerCount; ++i) {
            ActorRef ar = getContext().actorOf(Props.create(Slave.class), "Slave" + i);
            getContext().watch(ar);
            actorRefs.add(new ActorRefRoutee(ar));
        }
        router = new Router(new RoundRobinRoutingLogic(), actorRefs);
        this.listener = listener;
        receive(ReceiveBuilder.match(Calculator.class, msg -> !msg.isCalculated, msg ->
                IntStream.range(0, trunkCount)
                        .boxed()
                        .forEach(i -> router.route(new Calculator(i, trunkSize), self())))
                .match(Calculator.class, msg -> msg.isCalculated, msg -> {
                    result += msg.result;
                    resultCount += 1;
                    if(resultCount == trunkCount) {
                        Duration duration = Duration.ofMillis(System.currentTimeMillis() - startTime);
                        listener.tell(result + " " + duration.toString(), self());
                        getContext().stop(self());
                    }
                }).build());
    }
}

private static class Listener extends AbstractActor {
    public Listener() {
        receive(ReceiveBuilder.match(String.class, msg -> {
            LoggingHandler.info(msg.toString());
            //akka system clean up code here, omi
        }).build());
    }

}

public void run() {
    final int workerCount = Integer.parseInt(AppConfig.getProperties("workerCount"));
    final int trunkCount = Integer.parseInt(AppConfig.getProperties("trunkCount"));
    final int trunkSize = Integer.parseInt(AppConfig.getProperties("trunkSize"));
    ActorSystem as = ActorSystem.create("AkkaTry");
    final ActorRef listener = as.actorOf(Props.create(Listener.class), "Listener");
    ActorRef master = as.actorOf(Props.create(Master.class, () -> new Master(listener, workerCount, trunkCount, trunkSize)), "Master");
    ActorRef master2 = as.actorOf(Props.create(Master.class, () -> new Master(listener, 1, 1, trunkCount * trunkSize)), "Master2");
    master.tell(new Calculator(0, 0), master);
    master2.tell(new Calculator(0, 0), master2);
}

public static void main() {
    new Pi().run();

}
}
package Citi.CAG.MIFID.AkkaTry;
导入Citi.CAG.MIFID.Common.AppConfig.AppConfig;
导入Citi.CAG.MIFID.Common.Log.LoggingHandler;
导入akka.actor.*;
导入akka.event.Logging;
导入akka.event.LoggingAdapter;
导入akka.japi.Creator;
导入akka.japi.pf.ReceiveBuilder;
导入akka.routing.ActorRefRoutee;
导入akka.routing.RoundRobinRoutingLogic;
导入akka.routing.Routee;
导入akka.routing.Router;
导入com.typesafe.config.ConfigFactory;
导入sun.rmi.runtime.Log;
导入java.time.Duration;
导入java.util.LinkedList;
导入java.util.function.Consumer;
导入java.util.stream.IntStream;
公共类Pi{
专用静态类计算器{
私有最终整数指数;
私人最终尺寸;
私有双结果=0;
私有布尔值isCalculated=false;
公共计算器(整数索引、整数大小){
这个指数=指数;
树干大小=大小;
}
public int getIndex(){
收益指数;
}
public int getTrunkSize(){
返回长度;
}
公共空间计算(){
对于(int i=索引*中继大小;i<(索引+1)*中继大小;++i){
结果+=4.0*(1-(i%2)*2)/(2*i+1);
}
isCalculated=真;
}
}
私有静态类从扩展AbstractActor{
专用双精度计算器(int start,int nrofements){
双acc=0.0;
对于(int i=开始*n元素;i{
//msg.result=calculatePiFor(msg.getIndex(),msg.getRunksize());
//msg.isCalculated=true;
msg.calculate();
sender().tell(msg,self());
}).build());
}
静态道具道具(){
返回Props.create(Slave.class,Slave::new);
}
}
私有静态类主控扩展AbstractActor{
私有int resultCount=0;
私有双结果=0.0d;
private final long startTime=System.currentTimeMillis();
私有最终ActorRef侦听器;
专用最终路由器;
公共主机(ActorRef侦听器、int-workerCount、int-trunkCount、int-trunkSize){
LinkedList actorRefs=新建LinkedList();
对于(int i=0;i!msg.isCalculated,msg->
IntStream.range(0,trunkCount)
.boxed()
.forEach(i->router.route(新计算器(i,trunkSize),self()))
.match(Calculator.class,msg->msg.isCalculated,msg->{
结果+=msg.result;
结果计数+=1;
if(resultCount==trunkCount){
Duration Duration=持续时间(System.currentTimeMillis()-startTime);
listener.tell(result+“”+duration.toString(),self());
getContext().stop(self());
}
}).build());
}
}
私有静态类侦听器扩展了AbstractActor{
公共侦听器(){
接收(ReceiveBuilder.match)(String.class,msg->{
LoggingHandler.info(msg.toString());
//akka系统清理代码在这里,omi
}).build());
}
}
公开募捐{
final int workerCount=Integer.parseInt(AppConfig.getProperties(“workerCount”);
final int trunkCount=Integer.parseInt(AppConfig.getProperties(“trunkCount”);
final int trunkSize=Integer.parseInt(AppConfig.getProperties(“trunkSize”);
ActorSystem as=ActorSystem.create(“AkkaTry”);
final-ActorRef-listener=as.actorOf(Props.create(listener.class),“listener”);
ActorRef master=as.actorOf(Props.create(master.class,()->新master(listener、workerCount、trunkCount、trunkSize)),“master”);
ActorRef master2=as.actorOf(Props.create(Master.class,()->新Master(listener,1,1,trunkCount*trunkSize)),“master2”);
告诉大师(新计算器(0,0),大师);
master2.tell(新计算器(0,0),master2);
}
公共静态void main(){
新建Pi().run();
}
}
在上面的代码中,我有两种计算方法,一种是在从属类中调用calculatePiFor()方法,另一种是在传入的Calculator类中调用calculate()方法。这种细微的差异会产生显著的性能差异

private static class Calculator {
    private final int index;
    private final int trunkSize;
    private double result = 0;
    private boolean isCalculated = false;
    public Calculator(int index, int size) {
        this.index = index;
        trunkSize = size;
    }

    public int getIndex() {
        return index;
    }

    public int getTrunkSize() {
        return trunkSize;
    }

    public void calculate() {
        double result = 0.0d;
        for(int i = index * trunkSize; i < (index + 1) * trunkSize; ++i) {
            result += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1);
        }
        isCalculated = true;
        this.result = result;
    }
}

private static class Slave extends AbstractActor  {

    private double calculatePiFor(int start, int nrOfElements) {
        double acc = 0.0;
        for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) {
            acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1);
        }
        return acc;
    }
    Slave() {
        receive(ReceiveBuilder.match(Calculator.class, msg -> {
            //msg.result = calculatePiFor(msg.getIndex(), msg.getTrunkSize());
            //msg.isCalculated = true;
            msg.calculate();
            sender().tell(msg, self());
        }).build());
    }

    static Props props() {
        return Props.create(Slave.class, Slave::new);
    }
}
私有静态类计算器{
私有最终整数指数;
私人最终尺寸;
私有双结果=0;
私有布尔值isCalculated=false;
公共计算器(整数索引、整数大小){
这个指数=指数;
树干大小=大小;
}
public int getIndex(){
收益指数;
}
public int getTrunkSize(){
返回长度;
}
公共空间计算(){
双结果=0.0d;
对于(int i=索引*中继大小;i<(索引+1)*中继大小;++i){
结果+=4.0*(1-(i%2)*2)/(2*i+1);
}
isCalculated=真;
this.result=结果;
}
}
私有静态类从扩展AbstractActor{
专用双精度计算器(int start,int nrofements){
双acc=0.0;
对于(int i=开始*n元素;i{