it-swarm-tr.com

Java'da instanceof kullanmanın performans etkisi

Bir uygulama üzerinde çalışıyorum ve bir tasarım yaklaşımı instanceof operatörünün aşırı derecede yoğun kullanılmasını içeriyor. OO tasarımının genellikle instanceof kullanmaktan kaçınmaya çalıştığını bildiğim halde, bu farklı bir hikaye ve bu soru tamamen performansla ilgili. Performans etkisi olup olmadığını merak ediyor muydum? Sadece == kadar hızlı mı?

Örneğin, 10 alt sınıfa sahip bir temel sınıfım var. Temel sınıfı alan tek bir fonksiyonda, sınıfın alt sınıfın bir örneği olup olmadığına bakar ve bir rutin yürütürüm. 

Bunu çözmeyi düşündüğüm diğer yollardan biri, bunun yerine ilkel bir "type id" tamsayısı kullanmak ve alt sınıfların kategorilerini temsil etmek için bir bit maskesi kullanmaktı ve sonra da "sınıf id" alt sınıfları ile bir bit maskesi karşılaştırması yapmaktı. kategoriyi temsil eden sabit maske.

instanceof, JVM tarafından bir şekilde bundan daha hızlı olması için optimize edildi mi? Java'ya bağlı kalmak istiyorum ancak uygulamanın performansı kritik. Daha önce bu yoldan geçen birisinin bir tavsiyede bulunması çok iyi olurdu. Çok fazla nitpicking mi yoksa optimize etmek için yanlış şeye mi odaklanıyorum?

282
Josh

Modern JVM/JIC derleyicileri, anlık, istisnaların ele alınması, yansıtma vb. Dahil olmak üzere geleneksel olarak "yavaş" işlemlerin çoğunun performans vuruşunu kaldırmıştır.

Donald Knuth'un yazdığı gibi, "Küçük verimleri unutmalıyız, zamanın% 97'sini söyleyelim: erken optimizasyon tüm kötülüklerin kaynağıdır." Anlık durumun performansı büyük olasılıkla bir sorun olmayacak, bu yüzden sorun olduğundan emin olana kadar egzotik geçici çözümler bularak zamanınızı boşa harcamayın.

246
Steve

Yaklaşım

Farklı uygulamaları değerlendirmek için bir kıyaslama programı yazdım:

  1. instanceof uygulaması (referans olarak) 
  2. soyut bir sınıfla yönlendirilen nesne ve bir test yöntemi @Override
  3. kendi tipi bir uygulamayı kullanmak
  4. getClass() == _.class uygulama

Ben 100 ısınma çağrısı, ölçüm altında 1000 yineleme ve 10 çatal ile benchmark çalıştırmak için jmh kullandım. Böylece her seçenek 10 000 kez ölçüldü, bu da MacBook Pro'daki tüm kıyaslamayı MacOS 10.12.4 ve Java 1.8 ile çalıştırmak için 12:18:57 sürüyor. Kriter her seçeneğin ortalama süresini ölçer. Daha fazla ayrıntı için GitHub'daki uygulamam 'a bakın. 

Tamlık adına: bu cevabın önceki sürümü ve benim ölçütüm var. 

Sonuçlar

 | Operasyon | İşlem başına nanosaniye cinsinden çalışma süresi | İnstanceof | 
 | -------------- | |------------------------- 'ine göre --------- | ------------------------ | 
 | KURUMSAL | 39,598 ± 0,022 ns/op | % 100,00 | 
 | GETCLASS | 39,687 ± 0,021 ns/op | % 100,22 | 
 | TİPİ | 46,295 ± 0,026 ns/op | % 116,91 | 
 | OO | 48,078 ± 0,026 ns/op | % 121,42 | 

tl; Dr.

Java 1.8'de instanceof en hızlı yaklaşımdır, getClass() çok yakındır. 

230
Michael Dorner

Sadece exampleOf performansının basit bir s.equals () ifadesinin bir dize nesnesine yalnızca bir harf ile çağrıldığını görmek için basit bir test yaptım.

10.000.000 döngüde exampleOf bana 63-96ms verdi ve dize eşittir bana 106-230ms verdi

Java jvm 6 kullandım.

Bu yüzden benim basit testimde bir karakter dizisi karşılaştırması yerine exampleOf yapmak daha hızlı.

dize yerine Integer'in .equals () yönteminin kullanılması bana aynı sonucu verdi.

72
Dan Mihai Ile

Performans etkisini belirleyecek maddeler şunlardır:

  1. İnstanceof operatörünün gerçek değerlere dönebileceği olası sınıfların sayısı
  2. Verilerinizin dağılımı - ilk veya ikinci denemede işlemlerin çoğu aniden çözülmüş mü? Önce gerçek işlemleri geri getirme olasılığını koymak isteyeceksin.
  3. Dağıtım ortamı. Sun Solaris'te çalışan VM, Sun'ın Windows JVM'sinden önemli ölçüde farklıdır. Solaris, varsayılan olarak 'sunucu' modunda, Windows ise istemci modunda çalışacaktır. Solaris'teki JIT optimizasyonları, tüm metotlara erişimi aynı kılar. 

Dört farklı gönderme yöntemi için bir microbenchmark oluşturdum . Solaris'in sonuçları şu şekildedir; daha küçük sayı daha hızlıdır:

InstanceOf 3156
class== 2925 
OO 3083 
Id 3067 
17
brianegge

En son sorunuzu cevaplamak: Bir profilci size söylemediği sürece, çok az zaman harcadığınızı söyleyemiyorsa: Evet, nitpicking.

İyileştirilmesi gerekmeyen bir şeyi optimize etmeyi düşünmeden önce: Algoritmanızı en okunaklı şekilde yazın ve çalıştırın. Jit-derleyici kendisini optimize etme şansını yakalayana kadar çalıştırın. Bu kod parçasıyla ilgili sorunlarınız varsa, en çok nereden kazanılacağınızı ve bunu en iyi hale getireceğinizi söylemek için bir profilleyici kullanın.

En iyi duruma getirme derleyicileri zaman zaman, darboğazları hakkında tahminlerin tamamen yanlış olması muhtemeldir.

Ve bu cevabın gerçek ruhuyla (ki yürekten inanıyorum): Jit-derleyici onu en iyi duruma getirme şansını yakaladığında, nasıl bir anlama geldiğini kesinlikle anlamadım.

Unuttum: Asla ilk koşuyu ölçmeyin.

16
Olaf Kock

Aynı sorum var, ancak benimkine benzer kullanım senaryosu için 'performans ölçütlerini' bulamadığım için daha fazla örnek kod yaptım. Donanımımda ve Java 6 & 7’de, instanceof ve 10mln yinelemeyi açma arasındaki fark

for 10 child classes - instanceof: 1200ms vs switch: 470ms
for 5 child classes  - instanceof:  375ms vs switch: 204ms

Bu nedenle, özellikle çok sayıda if-if-if ifadesinde çok daha yavaş olmakla birlikte, gerçek uygulamada fark önemsiz olacaktır.

import Java.util.Date;

public class InstanceOfVsEnum {

    public static int c1, c2, c3, c4, c5, c6, c7, c8, c9, cA;

    public static class Handler {
        public enum Type { Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, TypeA }
        protected Handler(Type type) { this.type = type; }
        public final Type type;

        public static void addHandlerInstanceOf(Handler h) {
            if( h instanceof H1) { c1++; }
            else if( h instanceof H2) { c2++; }
            else if( h instanceof H3) { c3++; }
            else if( h instanceof H4) { c4++; }
            else if( h instanceof H5) { c5++; }
            else if( h instanceof H6) { c6++; }
            else if( h instanceof H7) { c7++; }
            else if( h instanceof H8) { c8++; }
            else if( h instanceof H9) { c9++; }
            else if( h instanceof HA) { cA++; }
        }

        public static void addHandlerSwitch(Handler h) {
            switch( h.type ) {
                case Type1: c1++; break;
                case Type2: c2++; break;
                case Type3: c3++; break;
                case Type4: c4++; break;
                case Type5: c5++; break;
                case Type6: c6++; break;
                case Type7: c7++; break;
                case Type8: c8++; break;
                case Type9: c9++; break;
                case TypeA: cA++; break;
            }
        }
    }

    public static class H1 extends Handler { public H1() { super(Type.Type1); } }
    public static class H2 extends Handler { public H2() { super(Type.Type2); } }
    public static class H3 extends Handler { public H3() { super(Type.Type3); } }
    public static class H4 extends Handler { public H4() { super(Type.Type4); } }
    public static class H5 extends Handler { public H5() { super(Type.Type5); } }
    public static class H6 extends Handler { public H6() { super(Type.Type6); } }
    public static class H7 extends Handler { public H7() { super(Type.Type7); } }
    public static class H8 extends Handler { public H8() { super(Type.Type8); } }
    public static class H9 extends Handler { public H9() { super(Type.Type9); } }
    public static class HA extends Handler { public HA() { super(Type.TypeA); } }

    final static int cCycles = 10000000;

    public static void main(String[] args) {
        H1 h1 = new H1();
        H2 h2 = new H2();
        H3 h3 = new H3();
        H4 h4 = new H4();
        H5 h5 = new H5();
        H6 h6 = new H6();
        H7 h7 = new H7();
        H8 h8 = new H8();
        H9 h9 = new H9();
        HA hA = new HA();

        Date dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerInstanceOf(h1);
            Handler.addHandlerInstanceOf(h2);
            Handler.addHandlerInstanceOf(h3);
            Handler.addHandlerInstanceOf(h4);
            Handler.addHandlerInstanceOf(h5);
            Handler.addHandlerInstanceOf(h6);
            Handler.addHandlerInstanceOf(h7);
            Handler.addHandlerInstanceOf(h8);
            Handler.addHandlerInstanceOf(h9);
            Handler.addHandlerInstanceOf(hA);
        }
        System.out.println("Instance of - " + (new Date().getTime() - dtStart.getTime()));

        dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerSwitch(h1);
            Handler.addHandlerSwitch(h2);
            Handler.addHandlerSwitch(h3);
            Handler.addHandlerSwitch(h4);
            Handler.addHandlerSwitch(h5);
            Handler.addHandlerSwitch(h6);
            Handler.addHandlerSwitch(h7);
            Handler.addHandlerSwitch(h8);
            Handler.addHandlerSwitch(h9);
            Handler.addHandlerSwitch(hA);
        }
        System.out.println("Switch of - " + (new Date().getTime() - dtStart.getTime()));
    }
}
12
Xtra Coder

instanceof, sadece birkaç CPU talimatı alarak gerçekten hızlı.

Görünüşe göre, eğer bir X sınıfı yüklü alt sınıfı yoksa (JVM bilir), instanceof şu şekilde optimize edilebilir:

     x instanceof X    
==>  x.getClass()==X.class  
==>  x.classID == constant_X_ID

Ana maliyet sadece bir okuma!

X yüklü alt sınıfı varsa, birkaç okuma daha gerekir; Muhtemelen ortak yerleşimli oldukları için ekstra maliyet de çok düşük.

Herkese iyi haber!

8
irreputable

instanceof muhtemelen gerçek dünyadaki çoğu uygulamada basit bir eşittirden daha pahalıya mal olacak (yani instanceof'ın gerçekten gerekli olduğu yerlerdir) ve her yeni başlangıç ​​ders kitabı gibi, ortak bir yöntemi geçersiz kılarak çözemezsiniz. Yukarıdaki Demian öneriyor).

Neden? Çünkü muhtemelen gerçekleşecek olan şey, bazı işlevler sağlayan (diyelim ki, x, y ve z arabirimleri) ve bu arabirimlerden birini uygulayabilecek (ya da uygulamayacak) manipüle edebilecek bazı nesneleriniz olabilir ... ama dolaylı. Mesela, Bende var ki:

w x uzanır

Bir uygular w

B, A'yı uzatır

C, B'yi uzatır, y'yi uygular

D, C'yi uzatır, z'yi uygular

Diyelim ki, D'nin bir örneğini işliyoruz d. Bilgi İşlem (x ifadesi), d.getClass () komutunu almayı gerektirir, birinin == - x olup olmadığını bilmek için uyguladığı arabirimler arasında döngü yapmayı ve tüm ataları için yinelemeli olarak yapmazsa .... Bizim durumumuz, o ağacın genişliğini ilk defa keşfederseniz, y ve z'nin hiçbir şeyi uzatmadığını varsayarak en az 8 karşılaştırma yaparsınız ...

Gerçek dünyadaki bir türetme ağacının karmaşıklığı daha yüksek olabilir. Bazı durumlarda, JIT, mümkün olan her durumda, x'i uzatan bir şeyin örneği olarak çözülebiliyorsa, çoğunu en iyi duruma getirebilir. Gerçekçi, ancak, çoğu zaman o ağaç geçişi geçecek.

Bu bir sorun olursa, nesnenin somut sınıfını işleyen bir kapanışla ilişkilendirerek bunun yerine bir işleyici haritası kullanmanızı öneririm. Doğrudan bir eşleme lehine ağaç geçiş aşamasını kaldırır. Ancak, C.class için bir işleyici ayarladıysanız, yukarıdaki d nesnemin tanınmayacağına dikkat edin.

işte 2 sentim, umarım yardım ederler ...

5
Varkhan

instanceof çok etkilidir, bu yüzden performansınız acı çekmez. .. Ancak, çok sayıda instanc kullanmanız bir tasarım sorunu olduğunu gösterir.

XClass == String.class öğesini kullanabilirseniz, bu daha hızlı olur. Not: Final dersleri için instanc'a ihtiyacınız yoktur.

4
Peter Lawrey

Demian ve Paul iyi bir noktadan bahseder; ancak , çalıştırılacak kodun yerleştirilmesi, gerçekten verileri nasıl kullanmak istediğinize bağlı ...

Ben birçok şekilde kullanılabilecek küçük veri nesnelerinin büyük bir hayranıyım. Geçersiz kılma (polimorfik) yaklaşımını takip ederseniz, nesneleriniz yalnızca "tek yönlü" kullanılabilir.

Kalıpların girdiği yer burası ...

Her nesneden kendisini geçerken "sizi aramasını" istemek için çift gönderme (ziyaretçi şablonunda olduğu gibi) kullanabilirsiniz - bu nesnenin türünü çözecektir. Bununla birlikte (tekrar) tüm olası alt türlerle "şeyler" yapabilen bir sınıfa ihtiyacınız olacak.

İşlemek istediğiniz her alt tür için stratejileri kaydedebileceğiniz bir strateji deseni kullanmayı tercih ederim. Aşağıdaki gibi bir şey. Bunun yalnızca tam eşleşmeler için yardımcı olduğunu, ancak genişletilebilir olması avantajına sahip olduğunu unutmayın; üçüncü taraf katkıda bulunanlar kendi türlerini ve işleyicilerini ekleyebilir. (Bu, yeni paketlerin eklenebileceği OSGi gibi dinamik çerçeveler için iyidir)

Umarım bu başka fikirlere de ilham verir ...

package com.javadude.sample;

import Java.util.HashMap;
import Java.util.Map;

public class StrategyExample {
    static class SomeCommonSuperType {}
    static class SubType1 extends SomeCommonSuperType {}
    static class SubType2 extends SomeCommonSuperType {}
    static class SubType3 extends SomeCommonSuperType {}

    static interface Handler<T extends SomeCommonSuperType> {
        Object handle(T object);
    }

    static class HandlerMap {
        private Map<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>> handlers_ =
            new HashMap<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>>();
        public <T extends SomeCommonSuperType> void add(Class<T> c, Handler<T> handler) {
            handlers_.put(c, handler);
        }
        @SuppressWarnings("unchecked")
        public <T extends SomeCommonSuperType> Object handle(T o) {
            return ((Handler<T>) handlers_.get(o.getClass())).handle(o);
        }
    }

    public static void main(String[] args) {
        HandlerMap handlerMap = new HandlerMap();

        handlerMap.add(SubType1.class, new Handler<SubType1>() {
            @Override public Object handle(SubType1 object) {
                System.out.println("Handling SubType1");
                return null;
            } });
        handlerMap.add(SubType2.class, new Handler<SubType2>() {
            @Override public Object handle(SubType2 object) {
                System.out.println("Handling SubType2");
                return null;
            } });
        handlerMap.add(SubType3.class, new Handler<SubType3>() {
            @Override public Object handle(SubType3 object) {
                System.out.println("Handling SubType3");
                return null;
            } });

        SubType1 subType1 = new SubType1();
        handlerMap.handle(subType1);
        SubType2 subType2 = new SubType2();
        handlerMap.handle(subType2);
        SubType3 subType3 = new SubType3();
        handlerMap.handle(subType3);
    }
}
4

'instanceof' aslında + veya - gibi bir işleçtir ve kendi JVM bayt kodu komutunun olduğuna inanıyorum. Çok hızlı olmalı.

Bir nesnenin bir alt sınıfın örneği olup olmadığını test ettiğiniz bir anahtarınız varsa, tasarımınızın elden geçirilmesi gerekebilir. Alt sınıfa özgü davranışı alt sınıfların kendilerine doğru itmeyi düşünün.

4

Instanceof çok hızlı. Sınıf referansı karşılaştırması için kullanılan bir byte koduna kadar kaynar. Döngüde birkaç milyon instanceo deneyin ve kendiniz görün.

4
Apocalisp

Belirli bir JVM'nin nasıl bir örnek oluşturduğunu söylemek zor, ancak çoğu durumda, Nesneler yapılarla karşılaştırılabilir ve sınıflar da iyidir ve her nesne yapısının bir örnek olduğu sınıf yapısına bir işaretçisi vardır. Öyleyse aslında

if (o instanceof Java.lang.String)

aşağıdaki C kodları kadar hızlı olabilir

if (objectStruct->iAmInstanceOf == &Java_lang_String_class)

bir JIT derleyicisinin yerinde olduğunu ve düzgün bir iş yaptığını varsayalım.

Bunun yalnızca bir işaretçiye eriştiği, bir işaretçiyi belirli bir uzaklıktaki işaretleyiciye götürdüğünü ve bunu başka bir işaretçiyle karşılaştırarak (temelde 32 bit sayılara eşit olmak üzere test etmekle aynı), işlemin gerçekten yapılabileceğini söyleyebilirim çok hızlı ol.

Buna rağmen, JVM'ye çok fazla bağlı değil. Ancak, bu kodunuzdaki darboğaz işlemi olarak ortaya çıkarsa, JVM uygulamasının oldukça zayıf olduğunu düşünüyorum. JIT derleyicisi olmayan ve yalnızca kodunu yorumlayan bir kişi bile, neredeyse hiç bir zaman bir test yapamamak zorundadır.

3
Mecki

InstanceOf , zayıf Nesne Yönelimli tasarımın bir uyarısıdır.

Mevcut JVM'ler, exampleOf 'nin başlı başına bir performans endişesi olmadığı anlamına gelir. Kendinizi çok kullanıyorsanız, özellikle de çekirdek işlevsellik için kullanıyorsanız, muhtemelen tasarıma bakmanın tam zamanı. Daha iyi bir tasarıma yeniden yapılanmanın performansı (ve sadelik/bakım kolaylığı) kazanımları, gerçek exampleOf çağrısı için harcanan gerçek işlemci çevrimlerinden daha ağır basacaktır.

Çok küçük basit bir programlama örneği vermek.

if (SomeObject instanceOf Integer) {
  [do something]
}
if (SomeObject instanceOf Double) {
  [do something different]
}

Zayıf bir mimari mi, daha iyi bir seçim, SomeObject'in, her çocuk sınıfının bir yöntemi (doSomething) geçersiz kıldığı ve böylece kodun şöyle görüneceği iki çocuk sınıfının ana sınıfı olması olacaktı:

Someobject.doSomething();
3
Demian Krige

Performans hakkında size geri döneceğim. Ancak, problemden (veya eksikliğinden) tamamen kaçınmanın bir yolu, üzerinde anlamanız gereken tüm alt sınıflara bir ana arayüz oluşturmak olacaktır. Arabirim, kontrol için anında yapmanız gereken alt sınıflardaki tümü yöntemlerinin süper bir kümesi olacaktır. Bir yöntemin belirli bir alt sınıfa uygulanmadığı durumlarda, bu yöntemin yapay bir uygulamasını sağlamanız yeterlidir. Eğer sorunu yanlış anlamadıysam, geçmişte problemi bu şekilde çözdüm. 

3
Jose Quijada

Genel olarak, "instanceof" operatörünün, böyle bir durumda kaşlarını çatmasının nedeni (örneğin, bu temel sınıfın alt sınıflarını kontrol ettiği yerde), yapmanız gereken şey, işlemleri bir yönteme taşımak ve uygun şekilde geçersiz kılmak olmasıdır alt sınıfları. Örneğin, eğer varsa:

if (o instanceof Class1)
   doThis();
else if (o instanceof Class2)
   doThat();
//...

İle değiştirebilirsiniz

o.doEverything();

ve daha sonra Class1 çağrısı "doThis ()" ve Class2 çağrısı "doThat ()" 'da "doEverything ()" uygulamasının yapılması.

2
Paul Tomblin

Modern Java sürümünde instanceof operatörü, basit bir yöntem çağrısı olarak daha hızlıdır. Bunun anlamı:

if(a instanceof AnyObject){
}

daha hızlı:

if(a.getType() == XYZ){
}

Başka bir şey ise, birçok örneği basamaklandırmanız gerekirse. Sonra sadece bir kez getType () çağıran bir anahtar daha hızlı olur.

2
Horcrux7

Jmh-Java-benchmark-arketipine dayanan bir performans testi yazıyorum: 2.21. JDK openjdk ve sürüm 1.8.0_212. Test makinesi mac pro. Test sonucu:

Benchmark                Mode  Cnt    Score   Error   Units
MyBenchmark.getClasses  thrpt   30  510.818 ± 4.190  ops/us
MyBenchmark.instanceOf  thrpt   30  503.826 ± 5.546  ops/us

Sonuç şunu gösterir: getClass, diğer teste aykırı olan exampleOf'tan daha iyidir. Ancak nedenini bilmiyorum.

Test kodu aşağıdadır:

public class MyBenchmark {

public static final Object a = new LinkedHashMap<String, String>();

@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean instanceOf() {
    return a instanceof Map;
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean getClasses() {
    return a.getClass() == HashMap.class;
}

public static void main(String[] args) throws RunnerException {
    Options opt =
        new OptionsBuilder().include(MyBenchmark.class.getSimpleName()).warmupIterations(20).measurementIterations(30).forks(1).build();
    new Runner(opt).run();
}
}
1
salexinx

Eğer hız sizin tek amacınızsa, o zaman alt sınıfları tanımlamak için int sabitleri kullanmak zamanın milisaniyesini tıraş ediyor gibi görünüyor

static final int ID_A = 0;
static final int ID_B = 1;
abstract class Base {
  final int id;
  Base(int i) { id = i; }
}
class A extends Base {
 A() { super(ID_A); }
}
class B extends Base {
 B() { super(ID_B); }
}
...
Base obj = ...
switch(obj.id) {
case  ID_A: .... break;
case  ID_B: .... break;
}

OO tasarımı korkunç; ancak performans analizin, bunun darboğazın nerede olduğunu gösteriyorsa belki de. Kodumda gönderme kodu toplam yürütme süresinin% 10'unu alıyor ve bu da% 1'lik bir hız artışına katkıda bulunmuş olabilir.

1
Salix alba

Ayrıca enum yaklaşımını tercih ediyorum, ancak alt sınıfları getType() yöntemini uygulamaya zorlamak için soyut bir temel sınıf kullanırdım.

public abstract class Base
{
  protected enum TYPE
  {
    DERIVED_A, DERIVED_B
  }

  public abstract TYPE getType();

  class DerivedA extends Base
  {
    @Override
    public TYPE getType()
    {
      return TYPE.DERIVED_A;
    }
  }

  class DerivedB extends Base
  {
    @Override
    public TYPE getType()
    {
      return TYPE.DERIVED_B;
    }
  }
}
0
mike

Bu sayfadaki genel fikir birliğine bir karşı örnek göndermenin “endişelendiğini” düşünmenin yeterince pahalı olmadığını düşündüm. İçsel bir döngü içinde bazı optimizasyonlar yaptım (bazı optimizasyon girişimlerinde)

if (!(seq instanceof SingleItem)) {
  seq = seq.head();
}

burada bir SingleItem üzerindeki head () işlevi değeri değişmeden döndürür. Kodu değiştirerek

seq = seq.head();

döngüde gerçekleşen bazı oldukça ağır şeyler olmasına rağmen, dize-çift dönüşümü gibi, bana 269ms'den 169ms'ye kadar bir hız kazandırıyor. Tabii ki hızlanma, koşullu dalın ortadan kaldırılmasından, operatörün kendisinin de ortadan kaldırılmasından daha fazla olabilir; ama bahsetmeye değer olduğunu düşündüm. 

0
Michael Kay

Peter Lawrey'in notuyla ilgili olarak, son sınıflar için instanc'a ihtiyacınız yok ve sadece bir referans eşitliği kullanabilirsiniz, dikkatli olun! Son sınıflar genişletilemese de, aynı sınıf yükleyici tarafından yüklenmeleri garanti edilmez. Sadece x.getClass () == SomeFinal.class veya ilk komutunu kullanın, ancak kodun bu bölümü için oyunda yalnızca bir sınıf yükleyici bulunduğundan eminseniz.

0
Miles Elam

Projenizde gerçekten bir performans sorunu olup olmadığını ölçmelisiniz/profil. Mümkünse eğer bir yeniden tasarımı tavsiye ederim. Platformun yerel uygulamasını geçemediğinizden eminim (C ile yazılmıştır). Ayrıca bu durumda çoklu mirası da düşünmelisiniz.

Sorun hakkında daha fazla şey söylemelisin, belki de ilişkisel mağaza kullanabilirsin. Sadece somut tiplerle ilgileniyorsanız, bir Harita <Sınıf, Nesne>.

0
Karl