it-swarm-tr.com

Daha hızlı, string açmak veya elseif üzerinde elseif nedir?

Diyelim ki bir dize karşılaştırmasına dayanarak bir kod yolu belirleme seçeneğine sahibim ya da türü iffed:

Hangisi daha hızlı ve neden?

switch(childNode.Name)
{
    case "Bob":
      break;
    case "Jill":
      break;
    case "Marko":
      break;
}

if(childNode is Bob)
{
}
elseif(childNode is Jill)
{
}
else if(childNode is Marko)
{
}

Güncelleme: Bunu sormamın ana nedeni, switch ifadesinin bir vaka olarak neyin önemli olduğuna dair delil olması. Örneğin, değişkenleri kullanmanıza izin vermez, sadece ana montaja taşınan sabitleri kullanır. Yaptığı bazı funky şeyler nedeniyle bu kısıtlama olduğunu varsaydım. Sadece başkalarına tercüme ediyorsa (bir posterin yorumuna göre) öyleyse neden durum açıklamalarında değişkenlere izin verilmiyor?

Caveat: Post-optimizasyon yapıyorum. Bu yönteme uygulamanın yavaş bir bölümünde [ defa denir.

72
Quibblesome

Greg'in profil sonuçları, içerdiği tam senaryo için mükemmeldir, ancak ilginç bir şekilde, farklı yöntemlerin nispi maliyetleri, karşılaştırılan tiplerin sayısı ve temel verilerdeki nispi frekans ve herhangi bir kalıp dahil olmak üzere bir dizi farklı faktör göz önüne alındığında çarpıcı bir şekilde değişir. .

Basit cevap, hiç kimsenin size özel senaryoda performans farkının ne olacağını söyleyemeyeceği, doğru bir cevap alabilmeniz için performansı kendi sisteminizde farklı yollarla ölçmeniz gerekecektir.

If/Else zinciri, az sayıda tip karşılaştırması için etkili bir yaklaşımdır veya gördüğünüz kişilerin çoğunluğunu hangi birkaç tipin oluşturacağını güvenilir bir şekilde tahmin edebiliyorsanız. Yaklaşımla ilgili olası sorun, tür sayısı arttıkça, yapılması gereken karşılaştırma sayısının da artmasıdır.

eğer aşağıdakileri uygularsam:

int value = 25124;
if(value == 0) ...
else if (value == 1) ...
else if (value == 2) ...
...
else if (value == 25124) ... 

doğru blok girilmeden önce koşulların değerlendirilmesi gerektiğinde önceki her biri. Diğer yandan

switch(value) {
 case 0:...break;
 case 1:...break;
 case 2:...break;
 ...
 case 25124:...break;
}

doğru bit koduna basit bir atlama yapacaktır.

Örneğinizde daha karmaşık hale geldiği yer, diğer yönteminizin biraz daha karmaşık hale gelebilecek tamsayılardan ziyade dizgelerde bir anahtar kullanmasıdır. Düşük seviyede, dizgiler tamsayı değerleriyle aynı şekilde açılamaz, böylece C # derleyicisi bu işi sizin için yapmak için bir sihir yapar. 

Switch ifadesi "yeterince küçükse" (derleyicinin otomatik olarak en iyi olduğunu düşündüğü şeyi yaparsa) dizeleri açmak, if/else zinciriyle aynı olan kodu oluşturur.

switch(someString) {
    case "Foo": DoFoo(); break;
    case "Bar": DoBar(); break;
    default: DoOther; break;
}

aynıdır:

if(someString == "Foo") {
    DoFoo();
} else if(someString == "Bar") {
    DoBar();
} else {
    DoOther();
}

Sözlükteki öğelerin listesi "yeterince büyük" olduğunda, derleyici otomatik olarak anahtardaki dizgilerden bir tamsayı indeksine eşleştiren bir iç sözlük ve ardından bu dizine dayalı bir anahtar oluşturur.

Buna benziyor (Yazmaya zahmet edeceğimden daha fazla giriş hayal et)

Statik bir alan, Dictionary<string, int> türündeki switch ifadesini içeren ve karıştırılmış bir ad verilen sınıfla ilişkilendirilen "gizli" bir konumda tanımlanır 

//Make sure the dictionary is loaded
if(theDictionary == null) { 
    //This is simplified for clarity, the actual implementation is more complex 
    // in order to ensure thread safety
    theDictionary = new Dictionary<string,int>();
    theDictionary["Foo"] = 0;
    theDictionary["Bar"] = 1;
}

int switchIndex;
if(theDictionary.TryGetValue(someString, out switchIndex)) {
    switch(switchIndex) {
    case 0: DoFoo(); break;
    case 1: DoBar(); break;
    }
} else {
    DoOther();
}

Yeni koştuğum bazı hızlı testlerde, If/Else yöntemi, 3 farklı tür için (türlerin rasgele dağıtıldığı) en az 3 kat daha hızlıdır. 25 tipte, anahtar 50 tipte küçük bir farkla (% 16) daha hızlıdır, anahtar iki kat daha hızlıdır.

Çok sayıda tip açacaksanız, 3. bir yöntem öneririm:

private delegate void NodeHandler(ChildNode node);

static Dictionary<RuntimeTypeHandle, NodeHandler> TypeHandleSwitcher = CreateSwitcher();

private static Dictionary<RuntimeTypeHandle, NodeHandler> CreateSwitcher()
{
    var ret = new Dictionary<RuntimeTypeHandle, NodeHandler>();

    ret[typeof(Bob).TypeHandle] = HandleBob;
    ret[typeof(Jill).TypeHandle] = HandleJill;
    ret[typeof(Marko).TypeHandle] = HandleMarko;

    return ret;
}

void HandleChildNode(ChildNode node)
{
    NodeHandler handler;
    if (TaskHandleSwitcher.TryGetValue(Type.GetRuntimeType(node), out handler))
    {
        handler(node);
    }
    else
    {
        //Unexpected type...
    }
}

Bu, Ted Elliot'ın önerdiğine benzer, ancak tam tür nesneler yerine çalışma zamanı türü tanıtıcılarının kullanılması, yazım nesnesini yansıtma yoluyla yüklemenin ek yükünü önler.

İşte makinemde bazı hızlı zamanlamalar:

 5.000.000 veri elemanı (mod = Rastgele) ve 5 türden oluşan 3 yinelemenin test edilmesi... Optimal 
 Yöntem Zamanının% 'si./Else 179.67 100.00 
 TypeHandleDictionary 321.33 178.85 
 TypeDictionary 377.67 210.20 
 492.67 274.21 
.__ 3. 5.000.000 veri elemanı (mod = Rastgele) ve 10 tip .__ ile 3 yinelemenin test edilmesi. Optimal .__% Metod Süresi./Else 271.33 100.00 
 TipHandleDictionary 312.00 114.99 
 TipDictionary 374.33 137.96 
 Anahtar 490.33 180.71 

. 5.000.000 veri öğesi (mod = Rastgele) ve 15 tip .__ ile 3 tekrarlamanın test edilmesi. Optimum 
 Metot Süresi%. TipHandleDictionary 312.00 100.00 
 Eğer/Başka 369.00 118.27 
 TypeDictionary 371.67 119.12 
 Switch 491.67 157.59 

. 3 yinelemenin 5.000.000 veri öğesiyle (mod = Rastgele) ve 20 tip .__ ile test edilmesi. ypeHandleDictionary 335.33 100.00 
 TypeDictionary 373.00 111.23 
 Eğer/Else 462.67 137.97 
 Anahtar 490.33 146.22 

 3 iterasyonun 5.000.000 eleman ile test edilmesi (mod = Rastgele) ve 25 tip 
 Yöntem Zaman% optimal 
 TypeHandleDictionary 319.33 100.00 
 TypeDictionary 371.00 116.18 
 Switch 483.00 151.25 
/Başkaları ise 562.00 175.99 

. 5.000.000 veri elemanı (mod = Rastgele) ve 50 tipte 3 tekrarlamanın test edilmesi
 Yöntem optimal zamanın% 'si... TipHandleDictionary 319.67 100.00 
 TypeDictionary 376.67 117.83 
 Switch 453.33 141.81 
/Ifse 1.032.67 323.04 

En azından makinemde, type handle dictionary yaklaşımı, yönteme girdi olarak kullanılan türlerin dağılımı rastgele olduğunda, 15 farklı türden daha fazlası için diğerlerini yener.

Öte yandan, girdi tamamen, eğer ilk önce if/else zincirinde kontrol edilen tipten oluşuyorsa, bu yöntem çok hızlı: 

5.000.000 veri elemanı (mode = UniformFirst) ve 50 tip .__ ile 3 yineleme testi.. Optimal Yöntem Zamanının% 'si. Eğer/Başka ise 39.00 100.00 TypeHandleDictionary 317.33 813.68 TypeDictionary 396.00 1.015.38 Switch 403.00 1,033.33

Tersine, eğer girdi her zaman if/else zincirindeki son şeyse, bunun tersi bir etkisi olur:

5.000.000 veri elemanı (mod = UniformLast) ve 50 tip .__ ile 3 yineleme testi. Optimal Metot Süresi%.. TypeHandleDictionary 317.67 100.00 Switch 354.33 111.54 TypeDictionary 377.67 118.89 If/Else 1,907.67 600,52

Girişinizle ilgili bazı varsayımlar yapabilirseniz, en iyi performansı, en yaygın olan birkaç tip için kontrol edip etmediğini ve ardından başarısız olursa sözlüğe dayalı bir yaklaşıma geri döndüğünüz hibrit yaklaşımdan en iyi performansı elde edebilirsiniz.

If you can make some assumptions about your input, you might get the best performance from a hybrid approach where you perform if/else checks for the few types that are most common, and then fall back to a dictionary-driven approach if those fail.

122
Andrew

Hızlı bir test uygulaması yaptım ve ANTS 4 ile profillendirdim.
Spec: .Net 3.5 sp1, 32bit Windows XP'de, yayın modunda yerleşik kod.

3 milyon test: 

  • Anahtar: 1.842 saniye
  • Eğer: 0.344 saniye.

Ayrıca, switch ifadesi, daha uzun isimlerin daha uzun sürdüğünü (şaşırtıcı olmayan bir şekilde) ortaya koymaktadır.

1 milyon test 

  • Bob: 0.612 saniye. 
  • Jill: 0,835 saniye. 
  • Marko: 1.093 saniye.

"Eğer Else" daha hızlıysa, en azından yarattığım senaryo gibi gözüküyorum. 

class Program
{
    static void Main( string[] args )
    {
        Bob bob = new Bob();
        Jill jill = new Jill();
        Marko marko = new Marko();

        for( int i = 0; i < 1000000; i++ )
        {
            Test( bob );
            Test( jill );
            Test( marko );
        }
    }

    public static void Test( ChildNode childNode )
    {   
        TestSwitch( childNode );
        TestIfElse( childNode );
    }

    private static void TestIfElse( ChildNode childNode )
    {
        if( childNode is Bob ){}
        else if( childNode is Jill ){}
        else if( childNode is Marko ){}
    }

    private static void TestSwitch( ChildNode childNode )
    {
        switch( childNode.Name )
        {
            case "Bob":
                break;
            case "Jill":
                break;
            case "Marko":
                break;
        }
    }
}

class ChildNode { public string Name { get; set; } }

class Bob : ChildNode { public Bob(){ this.Name = "Bob"; }}

class Jill : ChildNode{public Jill(){this.Name = "Jill";}}

class Marko : ChildNode{public Marko(){this.Name = "Marko";}}
18
Greg

Öncelikle, elmaları ve portakalları karşılaştırıyorsunuz. Öncelikle vs anahtarını açıp string'de, sonra da vs üzerinde string'i açıp sonra kazananları karşılaştırmanız gerekir.

İkincisi, bu OO için tasarlanan türden bir şey. OO'yu destekleyen dillerde, herhangi bir türün (her türden) açılması, zayıf tasarıma işaret eden bir kod kokusudur. Çözüm, soyut veya sanal bir yöntemle (veya dilinize bağlı olarak benzer bir yapıyla) ortak bir temelden türetmektir.

Örneğin.

class Node
{
    public virtual void Action()
    {
        // Perform default action
    }
}

class Bob : Node
{
    public override void Action()
    {
        // Perform action for Bill
    }
}

class Jill : Node
{
    public override void Action()
    {
        // Perform action for Jill
    }
}

Daha sonra, switch ifadesini yapmak yerine, childNode.Action () işlevini çağırmanız yeterlidir.

17
ilitirit

Switch ifadesi if-else-if merderinden daha hızlı yürütülür. Bu derleyicinin switch deyimini en iyi duruma getirme yeteneğinden kaynaklanmaktadır. İf-else-if merdiveni durumunda, kod her if ifadesini programcı tarafından belirlenen sırayla işlemelidir. Bununla birlikte, bir switch ifadesindeki her vaka daha önceki vakalara dayanmadığından, derleyici testi en hızlı işlemi sağlayacak şekilde yeniden düzenleyebilir.

12
Nescio

Sınıfları yaptıysanız, switch veya elseif yerine bir Strategy design pattern kullanmanızı öneririm.

6
Gary Kephart

Her nesne için sayıları kullanmayı deneyin, sayıları hızlı ve kolay bir şekilde açabilirsiniz.

4
Rick Minerich

Bunu daha önce yazmadıysanız ve performans sorununuzu bulamazsanız, hangisinin daha hızlı olduğunu merak etmem. Daha okunaklı olanla git. Unutmayın, "Erken optimizasyon tüm kötülüklerin köküdür." - Donald Knuth

3
Chris Upchurch

Bir SWITCH yapısı başlangıçta tamsayı verisi için tasarlanmıştı; amaç, argümanı doğrudan bir “gönderme tablosu” na, bir işaretçiler tablosuna bir indeks olarak kullanmaktı. Bu nedenle, tek bir test olacak, ardından bir dizi test yerine doğrudan ilgili koda başlatacaksınız.

Buradaki zorluk, kullanımının açıkça bir indeks olarak kullanılamayan "string" türlerine yaygınlaştırılmış olması ve SWITCH yapısının tüm avantajlarının kaybolmasıdır.

Hız, hedeflediğiniz amaç ise, sorun sizin kodunuz DEĞİL, veri yapınızdır. "Name" alanı gösterdiğiniz kadar basitse, bir tam sayı değerine kodlamak daha iyidir (örneğin, veriler oluşturulduğunda) ve bu tamsayıyı "uygulamanın yavaş bir bölümünde birçok kez" kullanmak için kullanın.

3
user17983

Açtığınız türler ilkel .NET türleri ise Type.GetTypeCode (Type) kullanabilirsiniz, ancak özel türlerse hepsi TypeCode.Object olarak geri gelir. 

Delegelerin veya işleyici sınıflarının bulunduğu bir sözlük de işe yarayabilir.

Dictionary<Type, HandlerDelegate> handlers = new Dictionary<Type, HandlerDelegate>();
handlers[typeof(Bob)] = this.HandleBob;
handlers[typeof(Jill)] = this.HandleJill;
handlers[typeof(Marko)] = this.HandleMarko;

handlers[childNode.GetType()](childNode);
/// ...

private void HandleBob(Node childNode) {
    // code to handle Bob
}
3
Ted Elliott

Çözümümü göstermek için sadece hız farkını vurgulamak için küçük bir konsol yarattım. Sertifika sürümü çalışma zamanında benim için yavaşladığından ve kopyalar düşükse ve eğer öyleyse switch anahtarım başarısız olursa (şimdiye kadar hiç olmadı) farklı bir dize karma algoritması kullandım. Benzersiz karma uzatma yöntemim aşağıdaki koda dahil edilmiştir.

 Core 2 console app with output

Özel kod kullanırken, her an, her zaman 695 kenenin üzerinde 29 onay alacağım.

Belirli bir veritabanındaki bir dizi dizeyle, kodunuzda kullanmanız için verilen bir dosyada sabit oluşturmak için küçük bir uygulama oluşturabilirsiniz, eğer değerler eklenirse, sadece toplu işinizi yeniden çalıştırın ve sabitler tarafından oluşturulur ve alınır. çözüm.

  public static class StringExtention
    {
        public static long ToUniqueHash(this string text)
        {
            long value = 0;
            var array = text.ToCharArray();
            unchecked
            {
                for (int i = 0; i < array.Length; i++)
                {
                    value = (value * 397) ^ array[i].GetHashCode();
                    value = (value * 397) ^ i;
                }
                return value;
            }
        }
    }

    public class AccountTypes
    {

        static void Main()
        {
            var sb = new StringBuilder();

            sb.AppendLine($"const long ACCOUNT_TYPE = {"AccountType".ToUniqueHash()};");
            sb.AppendLine($"const long NET_LIQUIDATION = {"NetLiquidation".ToUniqueHash()};");
            sb.AppendLine($"const long TOTAL_CASH_VALUE = {"TotalCashValue".ToUniqueHash()};");
            sb.AppendLine($"const long SETTLED_CASH = {"SettledCash".ToUniqueHash()};");
            sb.AppendLine($"const long ACCRUED_CASH = {"AccruedCash".ToUniqueHash()};");
            sb.AppendLine($"const long BUYING_POWER = {"BuyingPower".ToUniqueHash()};");
            sb.AppendLine($"const long EQUITY_WITH_LOAN_VALUE = {"EquityWithLoanValue".ToUniqueHash()};");
            sb.AppendLine($"const long PREVIOUS_EQUITY_WITH_LOAN_VALUE = {"PreviousEquityWithLoanValue".ToUniqueHash()};");
            sb.AppendLine($"const long GROSS_POSITION_VALUE ={ "GrossPositionValue".ToUniqueHash()};");
            sb.AppendLine($"const long REQT_EQUITY = {"ReqTEquity".ToUniqueHash()};");
            sb.AppendLine($"const long REQT_MARGIN = {"ReqTMargin".ToUniqueHash()};");
            sb.AppendLine($"const long SPECIAL_MEMORANDUM_ACCOUNT = {"SMA".ToUniqueHash()};");
            sb.AppendLine($"const long INIT_MARGIN_REQ = { "InitMarginReq".ToUniqueHash()};");
            sb.AppendLine($"const long MAINT_MARGIN_REQ = {"MaintMarginReq".ToUniqueHash()};");
            sb.AppendLine($"const long AVAILABLE_FUNDS = {"AvailableFunds".ToUniqueHash()};");
            sb.AppendLine($"const long EXCESS_LIQUIDITY = {"ExcessLiquidity".ToUniqueHash()};");
            sb.AppendLine($"const long CUSHION = {"Cushion".ToUniqueHash()};");
            sb.AppendLine($"const long FULL_INIT_MARGIN_REQ = {"FullInitMarginReq".ToUniqueHash()};");
            sb.AppendLine($"const long FULL_MAINTMARGIN_REQ ={ "FullMaintMarginReq".ToUniqueHash()};");
            sb.AppendLine($"const long FULL_AVAILABLE_FUNDS = {"FullAvailableFunds".ToUniqueHash()};");
            sb.AppendLine($"const long FULL_EXCESS_LIQUIDITY ={ "FullExcessLiquidity".ToUniqueHash()};");
            sb.AppendLine($"const long LOOK_AHEAD_INIT_MARGIN_REQ = {"LookAheadInitMarginReq".ToUniqueHash()};");
            sb.AppendLine($"const long LOOK_AHEAD_MAINT_MARGIN_REQ = {"LookAheadMaintMarginReq".ToUniqueHash()};");
            sb.AppendLine($"const long LOOK_AHEAD_AVAILABLE_FUNDS = {"LookAheadAvailableFunds".ToUniqueHash()};");
            sb.AppendLine($"const long LOOK_AHEAD_EXCESS_LIQUIDITY = {"LookAheadExcessLiquidity".ToUniqueHash()};");
            sb.AppendLine($"const long HIGHEST_SEVERITY = {"HighestSeverity".ToUniqueHash()};");
            sb.AppendLine($"const long DAY_TRADES_REMAINING = {"DayTradesRemaining".ToUniqueHash()};");
            sb.AppendLine($"const long LEVERAGE = {"Leverage".ToUniqueHash()};");
            Console.WriteLine(sb.ToString());

            Test();    
        }    

        public static void Test()
        {
            //generated constant values
            const long ACCOUNT_TYPE = -3012481629590703298;
            const long NET_LIQUIDATION = 5886477638280951639;
            const long TOTAL_CASH_VALUE = 2715174589598334721;
            const long SETTLED_CASH = 9013818865418133625;
            const long ACCRUED_CASH = -1095823472425902515;
            const long BUYING_POWER = -4447052054809609098;
            const long EQUITY_WITH_LOAN_VALUE = -4088154623329785565;
            const long PREVIOUS_EQUITY_WITH_LOAN_VALUE = 6224054330592996694;
            const long GROSS_POSITION_VALUE = -7316842993788269735;
            const long REQT_EQUITY = -7457439202928979430;
            const long REQT_MARGIN = -7525806483981945115;
            const long SPECIAL_MEMORANDUM_ACCOUNT = -1696406879233404584;
            const long INIT_MARGIN_REQ = 4495254338330797326;
            const long MAINT_MARGIN_REQ = 3923858659879350034;
            const long AVAILABLE_FUNDS = 2736927433442081110;
            const long EXCESS_LIQUIDITY = 5975045739561521360;
            const long CUSHION = 5079153439662500166;
            const long FULL_INIT_MARGIN_REQ = -6446443340724968443;
            const long FULL_MAINTMARGIN_REQ = -8084126626285123011;
            const long FULL_AVAILABLE_FUNDS = 1594040062751632873;
            const long FULL_EXCESS_LIQUIDITY = -2360941491690082189;
            const long LOOK_AHEAD_INIT_MARGIN_REQ = 5230305572167766821;
            const long LOOK_AHEAD_MAINT_MARGIN_REQ = 4895875570930256738;
            const long LOOK_AHEAD_AVAILABLE_FUNDS = -7687608210548571554;
            const long LOOK_AHEAD_EXCESS_LIQUIDITY = -4299898188451362207;
            const long HIGHEST_SEVERITY = 5831097798646393988;
            const long DAY_TRADES_REMAINING = 3899479916235857560;
            const long LEVERAGE = 1018053116254258495;

            bool found = false;
            var sValues = new string[] {
              "AccountType"
              ,"NetLiquidation"
              ,"TotalCashValue"
              ,"SettledCash"
              ,"AccruedCash"
              ,"BuyingPower"
              ,"EquityWithLoanValue"
              ,"PreviousEquityWithLoanValue"
              ,"GrossPositionValue"
              ,"ReqTEquity"
              ,"ReqTMargin"
              ,"SMA"
              ,"InitMarginReq"
              ,"MaintMarginReq"
              ,"AvailableFunds"
              ,"ExcessLiquidity"
              ,"Cushion"
              ,"FullInitMarginReq"
              ,"FullMaintMarginReq"
              ,"FullAvailableFunds"
              ,"FullExcessLiquidity"
              ,"LookAheadInitMarginReq"
              ,"LookAheadMaintMarginReq"
              ,"LookAheadAvailableFunds"
              ,"LookAheadExcessLiquidity"
              ,"HighestSeverity"
              ,"DayTradesRemaining"
              ,"Leverage"
            };

            long t1, t2;
            var sw = System.Diagnostics.Stopwatch.StartNew();
            foreach (var name in sValues)
            {
                switch (name)
                {
                    case "AccountType": found = true; break;
                    case "NetLiquidation": found = true; break;
                    case "TotalCashValue": found = true; break;
                    case "SettledCash": found = true; break;
                    case "AccruedCash": found = true; break;
                    case "BuyingPower": found = true; break;
                    case "EquityWithLoanValue": found = true; break;
                    case "PreviousEquityWithLoanValue": found = true; break;
                    case "GrossPositionValue": found = true; break;
                    case "ReqTEquity": found = true; break;
                    case "ReqTMargin": found = true; break;
                    case "SMA": found = true; break;
                    case "InitMarginReq": found = true; break;
                    case "MaintMarginReq": found = true; break;
                    case "AvailableFunds": found = true; break;
                    case "ExcessLiquidity": found = true; break;
                    case "Cushion": found = true; break;
                    case "FullInitMarginReq": found = true; break;
                    case "FullMaintMarginReq": found = true; break;
                    case "FullAvailableFunds": found = true; break;
                    case "FullExcessLiquidity": found = true; break;
                    case "LookAheadInitMarginReq": found = true; break;
                    case "LookAheadMaintMarginReq": found = true; break;
                    case "LookAheadAvailableFunds": found = true; break;
                    case "LookAheadExcessLiquidity": found = true; break;
                    case "HighestSeverity": found = true; break;
                    case "DayTradesRemaining": found = true; break;
                    case "Leverage": found = true; break;
                    default: found = false; break;
                }

                if (!found)
                    throw new NotImplementedException();
            }
            t1 = sw.ElapsedTicks;
            sw.Restart();
            foreach (var name in sValues)
            {
                switch (name.ToUniqueHash())
                {
                    case ACCOUNT_TYPE:
                        found = true;
                        break;
                    case NET_LIQUIDATION:
                        found = true;
                        break;
                    case TOTAL_CASH_VALUE:
                        found = true;
                        break;
                    case SETTLED_CASH:
                        found = true;
                        break;
                    case ACCRUED_CASH:
                        found = true;
                        break;
                    case BUYING_POWER:
                        found = true;
                        break;
                    case EQUITY_WITH_LOAN_VALUE:
                        found = true;
                        break;
                    case PREVIOUS_EQUITY_WITH_LOAN_VALUE:
                        found = true;
                        break;
                    case GROSS_POSITION_VALUE:
                        found = true;
                        break;
                    case REQT_EQUITY:
                        found = true;
                        break;
                    case REQT_MARGIN:
                        found = true;
                        break;
                    case SPECIAL_MEMORANDUM_ACCOUNT:
                        found = true;
                        break;
                    case INIT_MARGIN_REQ:
                        found = true;
                        break;
                    case MAINT_MARGIN_REQ:
                        found = true;
                        break;
                    case AVAILABLE_FUNDS:
                        found = true;
                        break;
                    case EXCESS_LIQUIDITY:
                        found = true;
                        break;
                    case CUSHION:
                        found = true;
                        break;
                    case FULL_INIT_MARGIN_REQ:
                        found = true;
                        break;
                    case FULL_MAINTMARGIN_REQ:
                        found = true;
                        break;
                    case FULL_AVAILABLE_FUNDS:
                        found = true;
                        break;
                    case FULL_EXCESS_LIQUIDITY:
                        found = true;
                        break;
                    case LOOK_AHEAD_INIT_MARGIN_REQ:
                        found = true;
                        break;
                    case LOOK_AHEAD_MAINT_MARGIN_REQ:
                        found = true;
                        break;
                    case LOOK_AHEAD_AVAILABLE_FUNDS:
                        found = true;
                        break;
                    case LOOK_AHEAD_EXCESS_LIQUIDITY:
                        found = true;
                        break;
                    case HIGHEST_SEVERITY:
                        found = true;
                        break;
                    case DAY_TRADES_REMAINING:
                        found = true;
                        break;
                    case LEVERAGE:
                        found = true;
                        break;
                    default:
                        found = false;
                        break;
                }

                if (!found)
                    throw new NotImplementedException();
            }
            t2 = sw.ElapsedTicks;
            sw.Stop();
            Console.WriteLine($"String switch:{t1:N0} long switch:{t2:N0}");
            var faster = (t1 > t2) ? "Slower" : "faster";
            Console.WriteLine($"String switch: is {faster} than long switch: by {Math.Abs(t1-t2)} Ticks");
            Console.ReadLine();

        }

Birkaç referans kitabındaki if/else dallanmasının switch ifadesinden daha hızlı olduğunu okudum. Ancak, Blackwasp hakkında yapılan bir araştırma, switch ifadesinin gerçekten daha hızlı olduğunu gösteriyor: http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx

Gerçekte, tipik 3 ila 10 (veya daha fazla) ifadeyi karşılaştırıyorsanız, birini veya diğerini kullanarak herhangi bir gerçek performans kazancı olduğundan şüpheliyim.

Chris'in daha önce de söylediği gibi, okunabilirlik için gidin: Yazıda daha hızlı, string'i aç veya elseif nedir?

2
Metro Smurf

Anahtar (), eğer varsa, başka bir gruba eşdeğer koda derlenir. Dize karşılaştırmaları tür karşılaştırmalarından çok daha yavaş olacaktır.

2
moonshadow

Bence buradaki ana performans sorunu, anahtar bloğunda, dizeleri karşılaştırdığınız ve if-else bloğundaki türleri kontrol ettiğiniz ... "Patatesleri muzlarla karşılaştırıyor".

Bunu karşılaştırarak başlardım:

switch(childNode.Name)
{
    case "Bob":
        break;
    case "Jill":
        break;
    case "Marko":
      break;
}

if(childNode.Name == "Bob")
{}
else if(childNode.Name == "Jill")
{}
else if(childNode.Name == "Marko")
{}
2
SaguiItay

Polimorfizm için doğru tasarımın ne kadar hızlı olacağından emin değilim. 

interface INode
{
    void Action;
}

class Bob : INode
{
    public void Action
    {

    }
}

class Jill : INode
{
    public void Action
    {

    }
}

class Marko : INode
{
    public void Action
    {

    }
}

//Your function:
void Do(INode childNode)
{
    childNode.Action();
}

Switch ifadenizin ne yaptığını görmek daha iyi olacaktır. İşleviniz türdeki bir eylemle ilgili gerçekten bir şey değilse, her türdeki bir numaralandırmayı tanımlayabilirsiniz.

enum NodeType { Bob, Jill, Marko, Default }

interface INode
{
    NodeType Node { get; };
}

class Bob : INode
{
    public NodeType Node { get { return NodeType.Bob; } }
}

class Jill : INode
{
    public NodeType Node { get { return NodeType.Jill; } }
}

class Marko : INode
{
    public NodeType Node { get { return NodeType.Marko; } }
}

//Your function:
void Do(INode childNode)
{
    switch(childNode.Node)
    {
        case Bob:
          break;
        case Jill:
          break;
        case Marko:
          break;
        Default:
          throw new ArgumentException();
    }
}

Bunun, söz konusu iki yaklaşımdan da daha hızlı olması gerektiğini düşünüyorum. Nanosaniye sizin için önemliyse soyut sınıf yolunu denemek isteyebilirsiniz .

2
nawfal

Burada sadece cevapların listesini okuyordum ve switch yapısını if-else ve ternary ? operatörleriyle karşılaştıran bu kıyaslama testi değerini paylaşmak istedim.

O post ile ilgili neyi sevdiğim, yalnızca tek sol yapıları (örneğin, if-else) değil aynı zamanda çift ve üç seviyeli yapıları da (örn. if-else-if-else) karşılaştırmasıdır.

Sonuçlara göre, 8/9 test durumlarında if-else yapısı en hızlı olanıydı; switch yapısı, 5/9 test durumlarında en hızlı olana bağlandı. 

Öyleyse hız arıyorsanız if-else, gitmenin en hızlı yoludur.

0
Thrawn Wannabe

Unutma, profilci senin arkadaşın. Her tahminde bulunmak çoğu zaman zaman kaybıdır. ... BTW, JetBrains ' dotTrace profiler konusunda iyi bir deneyimim oldu. 

0
Eddie Velasquez

Dize açmak temelde bir if-else-if merdiveninde derlenir. Basit bir tane açmayı deneyin. Her durumda, test dizesi dengesinin test edilmesinden dolayı daha ucuz olması gerekir ve bunlar için tek gereken referans kontrolüdür. Bakım açısından mantıklı olanı yapın; dizeleri karşılaştırıyorsanız, dize anahtarını yapın. Türe göre seçiyorsanız, bir tür merdiveni daha uygun olur.

0
nimish

Dize karşılaştırması daima çalışma zamanı ortamına tamamen dayanır (dizeler statik olarak tahsis edilmediği sürece, bunları birbirleriyle karşılaştırmanız gerekebilir). Bununla birlikte, tür karşılaştırması dinamik veya statik ciltleme yoluyla yapılabilir ve çalışma ortamı için çalışma ortamı için karakter dizisindeki karakterleri karşılaştırmaktan daha verimlidir.

0
Magsol

Şüphesiz String'teki anahtar, bir tür karşılaştırmasından daha yavaş (ve anahtar/vaka için kullanılan tipik tamsayı karşılaştırmasından çok daha yavaş) olan bir String karşılaştırmasına (her durumda bir tane) derlenir.

0
JeeBee

Bunu biraz farklı yapıyorum, Açtığınız dizgiler sabit olacak, böylece derleme zamanında değerleri tahmin edebilirsiniz. 

senin durumunda hash değerlerini kullanırdım, bu bir int anahtarı, 2 seçeneğin var, derleme zamanı sabitlerini kullan veya çalışma zamanında hesapla.

//somewhere in your code
static long _bob = "Bob".GetUniqueHashCode();
static long _jill = "Jill".GetUniqueHashCode();
static long _marko = "Marko".GeUniquetHashCode();

void MyMethod()
{
   ...
   if(childNode.Tag==0)
      childNode.Tag= childNode.Name.GetUniquetHashCode()

   switch(childNode.Tag)
   {
       case _bob :
        break;
       case _jill :
         break;
       case _marko :
        break;
   }
}

GetUniquetHashCode için uzatma yöntemi şöyle olabilir:

public static class StringExtentions
    {
        /// <summary>
        /// Return unique Int64 value for input string
        /// </summary>
        /// <param name="strText"></param>
        /// <returns></returns>
        public static Int64 GetUniquetHashCode(this string strText)
        {
            Int64 hashCode = 0;
            if (!string.IsNullOrEmpty(strText))
            {
                //Unicode Encode Covering all character-set
                byte[] byteContents = Encoding.Unicode.GetBytes(strText);
                System.Security.Cryptography.SHA256 hash =  new System.Security.Cryptography.SHA256CryptoServiceProvider();
                byte[] hashText = hash.ComputeHash(byteContents);
                //32Byte hashText separate
                //hashCodeStart = 0~7  8Byte
                //hashCodeMedium = 8~23  8Byte
                //hashCodeEnd = 24~31  8Byte
                //and Fold
                Int64 hashCodeStart = BitConverter.ToInt64(hashText, 0);
                Int64 hashCodeMedium = BitConverter.ToInt64(hashText, 8);
                Int64 hashCodeEnd = BitConverter.ToInt64(hashText, 24);
                hashCode = hashCodeStart ^ hashCodeMedium ^ hashCodeEnd;
            }
            return (hashCode);
        }


    }

Bu kodun kaynağı yayınlandı burada Lütfen Kriptografinin kullanılmasının yavaş olduğunu, uygulama başlangıcında desteklenen dizgiyi ısındığınızı unutmayın, bunu değişmeyecek şekilde statik alanlarda kaydetmekteyim ve örnekle alakalı değil. lütfen düğüm nesnesinin etiket değerini ayarladığımı, herhangi bir özellik kullanabileceğimi veya bir tane ekleyebileceğimi, sadece bunların asıl metinle senkronize olduklarından emin olduğumu unutmayın. 

Düşük gecikmeli sistemler üzerinde çalışıyorum ve tüm kodlarım bir komut dizesi olarak geliyor: value, command: value .... 

şimdi komutun tümü 64 bit tamsayı değerleri olarak bilinir, bu nedenle böyle bir işlem yapmak biraz zaman kazandırır. 

Anahtarla ilgili sorunlarınızdan biri de "Bob" gibi dizgiler kullanmak, bu derlenmiş kodda daha fazla döngü ve çizgiye neden olacaktır. Üretilen IL bir dize bildirmek, "Bob" olarak ayarlamak ve sonra karşılaştırmada kullanmak zorunda kalacak. Bu nedenle, IF ifadeleriniz daha hızlı çalışacaktır.

PS. Aeon'un örneği işe yaramaz çünkü Çeşitlerini açamazsınız. (Hayır, tam olarak nedenini bilmiyorum ama denedik, işe yaramadı. Değişken türü ile ilgisi var)

Bunu test etmek istiyorsanız, ayrı bir uygulama oluşturun ve yukarıda yazılanları yapan ve ILdasm.exe gibi bir şey kullanarak IL'yi görmek için iki basit Yöntem oluşturun. IF deyiminin Yöntemi IL'sinde çok daha az satır olduğunu göreceksiniz.

Ildasm VisualStudio ile birlikte geliyor ... 

ILDASM sayfası - http://msdn.Microsoft.com/en-us/library/f7dy01k1(VS.80).aspx

ILDASM Eğitimi - http://msdn.Microsoft.com/en-us/library/aa309387(VS.71).aspx

0
Joe

Üç düşünce:

1) Nesnelerin türlerine göre farklı bir şey yapacaksanız, bu davranışı bu sınıflara taşımak mantıklı olabilir. Sonra, anahtar veya if-else yerine, yalnızca childNode.DoSomething () öğesini çağırırsınız. 

2) Türlerin karşılaştırılması dize karşılaştırmalarından çok daha hızlı olacaktır.

3) Eğer başka bir tasarımda, testleri yeniden sıralamanın avantajlarından yararlanabilirsiniz. Eğer "Jill" objeleri oradan geçen nesnelerin% 90'ını oluşturuyorsa, önce bunları test edin.

0
Mark Bessey