2015-03-12 25 views
10

Java 8'de monadic programlama daha yavaş mı? Aşağıda benim testim (her bir hesaplama için yeni örnekler yaratan sağa eğilimli bir yöntem kullanılır). Zorunlu sürüm 1000 kat daha hızlıdır. Karşılaştırılabilir performans alırken Java8'de monadicali nasıl programlayabilirim? Oldukça görünüşe yan etkileri map kullandığınız çaba – anlamak ve olmasak daKarşılaştırılabilir performans elde ederken Java8'de monadicaly'yi nasıl programlayabilirim?

Main.java

public class Main { 

    public static void main(String args[]){ 
     Main m = new Main(); 
     m.work(); 
     m.work2(); 
    } 


    public void work(){ 
     final long start = System.nanoTime(); 
     final Either<Throwable,Integer> result = 
       Try(this::getInput).flatMap((s) -> 
       Try(this::getInput).flatMap((s2) -> 
       parseInt(s).flatMap((i) -> 
       parseInt(s2).map((i2) -> 
       i + i2 
       )))); 
     final long end = System.nanoTime(); 
     result.map(this::println).leftMap(this::println); 
     System.out.println((end-start)/1000+"us to execute"); 
    } 

    public void work2(){ 
     Object result; 
     final long start = System.nanoTime(); 
     try { 
      final String s = getInput(); 
      final String s2 = getInput(); 

      final int i = parzeInt(s); 
      final int i2 = parzeInt(s2); 
      result = i + i2; 
     }catch(Throwable t){ 
      result=t; 
     } 
     final long end = System.nanoTime(); 
     println(result); 
     System.out.println((end-start)/1000+"us to execute"); 
    } 

    public <A> A println(final A a){ 
     System.out.println(a); 
     return a; 
    } 

    public String getInput(){ 
     final Integer value = new Random().nextInt(); 
     if(value % 2 == 0) return "Surprise!!!"; 
     return value+""; 
    } 

    public Either<Throwable,Integer> parseInt(final String s){ 
     try{ 
      return Either.right(Integer.parseInt(s)); 
     }catch(final Throwable t){ 
      return Either.left(t); 
     } 
    } 

    public Integer parzeInt(final String s){ 
     return Integer.parseInt(s); 
    } 
} 

Either.java

public abstract class Either<L,R> 
{ 
    public static <L,R> Either<L,R> left(final L l){ 
     return new Left(l); 
    } 

    public static <L,R> Either<L,R> right(final R r){ 
     return new Right(r); 
    } 

    public static<L,R> Either<L,R> toEither(final Optional<R> oR,final L l){ 
     return oR.isPresent() ? right(oR.get()) : left(l); 
    } 

    public static <R> Either<Throwable,R> Try(final Supplier<R> sr){ 
     try{ 
      return right(sr.get()); 
     }catch(Throwable t){ 
      return left(t); 
     } 
    } 

    public abstract <R2> Either<L,R2> flatMap(final Function<R,Either<L,R2>> f); 

    public abstract <R2> Either<L,R2> map(final Function<R,R2> f); 

    public abstract <L2> Either<L2,R> leftMap(final Function<L,L2> f); 

    public abstract Either<R,L> swap(); 

    public static class Left<L,R> extends Either<L,R> { 
     final L l; 

     private Left(final L l){ 
      this.l=l; 
     } 

     public <R2> Either<L,R2> flatMap(final Function<R,Either<L,R2>> f){ 
      return (Either<L,R2>)this; 
     } 

     public <R2> Either<L,R2> map(final Function<R,R2> f){ 
      return (Either<L,R2>)this; 
     } 

     public <L2> Either<L2,R> leftMap(final Function<L,L2> f){ 
      return new Left(f.apply(l)); 
     } 

     public Either<R,L> swap(){ 
      return new Right(l); 
     } 
    } 

    public static class Right<L,R> extends Either<L,R> { 
     final R r; 

     private Right(final R r){ 
      this.r=r; 
     } 

     public <R2> Either<L,R2> flatMap(final Function<R,Either<L,R2>> f){ 
      return f.apply(r); 
     } 

     public <R2> Either<L,R2> map(final Function<R,R2> f){ 
      return new Right(f.apply(r)); 
     } 

     public <L2> Either<L2,R> leftMap(final Function<L,L2> f){ 
      return (Either<L2,R>)this; 
     } 

     public Either<R,L> swap(){ 
      return new Left(r); 
     } 
    } 
} 
+5

Sadece birkaç kez daha çalışın. Bir lambda önyükleme pahalıdır. –

+1

1.000.000 çalışmayla, fark 10 kat daha yavaştır. Main.parseInt (String) 'de harcanan zamanın% 80'i ile, bir nedenle ... –

+0

, zaman deltasını döndürmek için çalışmayı değiştirdi. 1.000.000 koşular ve 10.000.000 koşular için koştu. Hala kabaca 1000 olan fark bulundu. Sadece son değerlendirmeyi aldım (oldukça sıcak olduğunda). Sonuçları aşağıdaki örneklerde görebilirsiniz: Func: 57411000 \t Imper: 83000 – jordan3

cevap

9

gerçekten hiç yok Alternatif olarak – yazımından sonuç elde etmek için alternatif çalışmanızı JMH'de olduğu gibi ölçtüm. Random kullanımınız yanlıştı, düzeltdim. Bu benim kullanılan kod:

@BenchmarkMode(Mode.AverageTime) 
@OutputTimeUnit(TimeUnit.NANOSECONDS) 
@OperationsPerInvocation(Measure.SIZE) 
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) 
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) 
@State(Scope.Thread) 
@Fork(1) 
public class Measure 
{ 
    static final int SIZE = 1; 

    @Benchmark public Either<Throwable, Integer> workMonadically() { 
    final Either<Throwable,Integer> result = 
     Try(this::getInput).flatMap((s) -> 
      Try(this::getInput).flatMap((s2) -> 
       parseInt(s).flatMap((i) -> 
        parseInt(s2).map((i2) -> 
          i + i2 
        )))); 
    return result; 
    } 

    @Benchmark public Object workImperatively() { 
    Object result; 
    try { 
     final String s = getInput(); 
     final String s2 = getInput(); 

     final int i = parzeInt(s); 
     final int i2 = parzeInt(s2); 
     result = i + i2; 
    }catch(Throwable t){ 
     result=t; 
    } 
    return result; 
    } 

    public String getInput() { 
    final Integer value = ThreadLocalRandom.current().nextInt(); 
    if (value % 2 == 0) return "Surprise!!!"; 
    return String.valueOf(value); 
    } 

    public Either<Throwable,Integer> parseInt(final String s){ 
    try{ 
     return Either.right(Integer.parseInt(s)); 
    }catch(final Throwable t){ 
     return Either.left(t); 
    } 
    } 

    public Integer parzeInt(final String s){ 
    return Integer.parseInt(s); 
    } 

    public static abstract class Either<L,R> 
    { 
    public static <L,R> Either<L,R> left(final L l){ 
     return new Left<>(l); 
    } 

    public static <L,R> Either<L,R> right(final R r){ 
     return new Right<>(r); 
    } 

    public static<L,R> Either<L,R> toEither(final Optional<R> oR,final L l){ 
     return oR.isPresent() ? right(oR.get()) : left(l); 
    } 

    public static <R> Either<Throwable,R> Try(final Supplier<R> sr){ 
     try{ 
     return right(sr.get()); 
     }catch(Throwable t){ 
     return left(t); 
     } 
    } 

    public abstract <R2> Either<L,R2> flatMap(final Function<R,Either<L,R2>> f); 

    public abstract <R2> Either<L,R2> map(final Function<R,R2> f); 

    public abstract <L2> Either<L2,R> leftMap(final Function<L,L2> f); 

    public abstract Either<R,L> swap(); 

    public static class Left<L,R> extends Either<L,R> { 
     final L l; 

     private Left(final L l){ 
     this.l=l; 
     } 

     @Override public <R2> Either<L,R2> flatMap(final Function<R,Either<L,R2>> f){ 
     return (Either<L,R2>)this; 
     } 

     @Override public <R2> Either<L,R2> map(final Function<R,R2> f){ 
     return (Either<L,R2>)this; 
     } 

     @Override public <L2> Either<L2,R> leftMap(final Function<L,L2> f){ 
     return new Left<>(f.apply(l)); 
     } 

     @Override public Either<R,L> swap(){ 
     return new Right<>(l); 
     } 
    } 

    public static class Right<L,R> extends Either<L,R> { 
     final R r; 

     private Right(final R r){ 
     this.r=r; 
     } 

     @Override public <R2> Either<L,R2> flatMap(final Function<R,Either<L,R2>> f){ 
     return f.apply(r); 
     } 

     @Override public <R2> Either<L,R2> map(final Function<R,R2> f){ 
     return new Right<>(f.apply(r)); 
     } 

     @Override public <L2> Either<L2,R> leftMap(final Function<L,L2> f){ 
     return (Either<L2,R>)this; 
     } 

     @Override public Either<R,L> swap(){ 
     return new Left<>(r); 
     } 
    } 
    } 
} 

ve bu sonucudur:

Benchmark     Mode Cnt  Score  Error Units 
Measure.workImperatively avgt 5 1646,874 ± 137,326 ns/op 
Measure.workMonadically avgt 5 1990,668 ± 281,646 ns/op 

Yani neredeyse hiç fark yok.

+0

"Neredeyse hiç fark yok"?!? ** Imperative% 15-20 daha hızlıdır. ** –

+0

@ Anony-Mousse "1000 kat daha hızlı" yüksekliğinden bakıldığında, "0.2 kat daha hızlı", "neredeyse hiç farketmez" gibi geliyor. Ve mutlak anlamda bile, herhangi bir pratik durumda böyle bir fark neredeyse göz ardı edilebilir. Ancak, OP'nin kodu yalnızca deyimler arasındaki farka yeterince odaklanmadığı için, bağlayıcı adımların saf genel giderlerinin oranının oldukça yüksek olmasını beklerim: daha çok 2-3 gibi. –

+0

Böyle küçük durumlarda, inline genellikle çalışır. Bu yüzden fark bundan daha fazla değil. Fakat daha karmaşık durumlarda, maalesef iyi bir şekilde birikebilir. Özellikle bir kez ',', akarsular, vb polimorf veya multimorf vb vardır. –