コードの温度差
2017/08/20コードの記述ミスを修正
さて、メリッサとジョージの温度差について説明する必要があるだろう。
そもそも、メリッサが言う”冗長な呪文”とは、このようなコードを言っている。
これは並の魔法使いが書くコードだ。
『
public static void main(String[] args){
List<Object> list = Magic.getTargetObjectList();
TheMark[] mark= new TheMark[2];
int markIndex=0;
for(int i = 0;i <list.size();i++){
Object object = list.get(i);
if(object instanceof TheMark){
TheMark tempMark = (TheMark)object;
mark[markIndex] = tempMark;
markIndex++;
}
}
for(int j = 0;j < 5;j++){
Missile missile1 = new Missile(1);
FireElement fire1 = new FireElement(200);
missile1.addElement(fire1);
missile1.setTarget(mark[0]);
missile1.start();
}
Object target2 = list.get(1);
for(int k = 0;k < 5;k++){
Missile missile2 = new Missile(1);
FireElement fire2 = new FireElement(-10);
missile2.addElement(fire2);
missile2.setTarget(mark[1]);
missile2.start();
}
}
』
いろいろと突っ込みどころがあるのを敢えてスルーして、結果だけ見ると、Effect(ここではMagic)の生成には時間コストが1秒ほど発生するため、単純に他の要素を無視しても、この呪文は1秒ごとに矢を生成し、発射し、命中してから再度生成し、と繰り返すため、(1生成時間+2距離時間)×10本でこれだけで30秒、実際にはそれ以外のコストがあるため20秒どころか30秒を切ることすらできない。
一方メリッサが競技に使用しようとしたコードはこうだ。
『
public static void main(String[] args){
List<Object> list=Magic.getTargetObjectList();
List<Object> markList=new ArrayList<Object>();
for(Object object:list)
if(object instanceof TheMark)
markList.add(object);
List<Effect> effectList=new ArrayList<Effect>();
int[] temperatures={200,-10};
for(int i=0,s=0;i<10;++i,s=1-s)
effectList.add(makeEffect(temperatures[s],markList.get(s)));
for(Effect effect:effectList)
effect.start();
}
private static Effect makeEffect(int temperature,Object target){
Effect effect=new Missile(1);
effect.addElement(new FireElement(temperature));
effect.setTarget(target);
return effect;
}
』
矢が出現するのはEffectのインスタンスが出来たタイミング、つまりnew Missile(1)が実行されたタイミングである。
よって、このコードを実行した場合、まず10秒かけて矢が10本できてから、その後発射、命中を繰り返す。
結果として10秒+2×10秒=30秒かかるので、最初のコードと変わらないように見えるが、これは”魔法が発動してから全てが当たるまでの時間”の理解の差によるものだ。
メリッサの言う”魔法が発動”、つまり魔法競技での”魔法が発動”とは、”効果を発揮した”の意味であり、今回の場合は”的に命中した瞬間”を意味していた。
この場合、最初のコードでは27秒かかるが、メリッサのコードは最初の1矢が命中したあとは2秒ごとに9本、つまり18秒+αが”魔法が発動してから全てが当たるまでの時間”となる。
では、ジョージが書いたコードはどうだったか。
『
public static void main(String[] args){
final TheMark[] targets=
Magic.getTargetObjectList()
.stream()
.filter(o->o instanceof TheMark)
.toArray(TheMark[]::new);
IntConsumer shooter=new IntConsumer(){
public void accept(int value) {
Effect effect=new Missile(1);
effect.addElement(new FireElement(value==0?200:-10));
effect.setTarget(targets[value]);
effect.start();
}
};
IntStream.iterate(0,n->1-n).parallel().limit(10).forEach(shooter::accept);
}
』
もはや逆の意味でどこから突っ込んだらいいのかわからない、(無駄に)関数インターフェースを駆使したJava8 Stream APIコードであった。
ジョージのコードでは矢の生成から命中までの3秒が並列に実行されます。
この並列には上限があり、PCであればコア数であったりスレッド数であったりというのが上限となります。
ただ、この世界では幸いなことにJDK Server VirtualMageが動作している場所は、超並列環境なので、並列可能数は”物凄い数”、となります。




