Diskuze: Rychlost deserializace JSONu a nahrání do listViewu (Windows Phone 8.1)

C# .NET .NET (C# a Visual Basic) Rychlost deserializace JSONu a nahrání do listViewu (Windows Phone 8.1) American English version English version

Avatar
Matyáš Černohous (Matesak):

Zdravím
dělám aplikaci pro Windows Phone 8.1 a pro komunikaci s databází použím Rest Api a JSON. Vše mi funguje, ale mám problém s rychlostí deserializace a načítání dat do listViewu. Když těch dat není moc, tak to jede relativně svižně, ale pokud je tam více než 100 položek čekám třeba i 3-4 sekundy na načtení. Neví někdo efektivnější způsob jak to vyřešit ? :)

Tady je kód deserializace a nahrání do ListViewu:

private async void ZobrazData(string json)
        {
            //MessageDialog msg = new MessageDialog(json);
            //await msg.ShowAsync();
            this.ListBox1.ItemsSource = null;

            CultureInfo culture = new CultureInfo("cs-CZ");

            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<dataInfo>));
            MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
            var obj = (List<dataInfo>)ser.ReadObject(stream);

            VypisZakazekli.Clear();

            foreach (dataInfo di in obj)
            {
                string barva = "";
                string iZakazka = di.zakazka;
                string sNazev = di.nazev;
                string sKod = di.kod_firmy;
                string sStatus = "Status: " + di.status_v;
                string sDruh = di.druh_zakazky;
                switch(di.barva)
                {
                    case "ZE": barva = "#FF32FF1D"; break;
                    case "CE": barva = "#FFFF1D1D"; break;
                    case "ZL": barva = "#FFF5FF1D"; break;
                    case "OR": barva = "#FFFFA31D"; break;
                    case "MO": barva = "#FF1D46FF"; break;
                    default: barva="x:Null"; break;

                }
                VypisZakazekli.Add(new dataInfo(iZakazka, sNazev, sKod, sStatus, sDruh,barva));
            }

            this.ListBox1.ItemsSource = VypisZakazekli;

        }

tady je moje dataInfo class

[DataContract]
   class dataInfo
   {
       [DataMember]
       public string zakazka { get; set; }
       [DataMember]
       public string nazev { get; set; }
       [DataMember]
       public string kod_firmy { get; set; }
       [DataMember]
       public string status_v { get; set; }
       [DataMember]
       public string druh_zakazky { get; set; }
       [DataMember]
       public string barva { get; set; }



       public dataInfo(string Zakazka, string Nazev, string Kod, string Status, string Druh, string Barva)
       {
           this.zakazka = Zakazka;
           this.nazev = Nazev;
           this.kod_firmy = Kod;
           this.status_v = Status;
           this.druh_zakazky = Druh;
           this.barva = Barva;

       }
   }
 
Odpovědět 25.9.2015 12:13
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Matyáš Černohous (Matesak)
patrik.valkovic:

Obávám se, že toho moc nevymyslíš.
Za prvé nevím, jak Serializer plní proměnnou. Jestli zavolá kontruktor se získanými parametry, nebo zavolá kontruktor a poté nastavuje každou poperty zvlášť. Když smažeš kontruktor, bude to fungovat? Pokud ano, znamenalo by to, že všechny attributy nastaví null a poté teprve přiřazuje property - ušetřil bys 6 operátorů přiřazení.
S tím souvisí také samotný cyklus, kde vlastně znovu vytváříš dataInfo. Co kdybys pouze přepsal původní attributy, které se mění?

foreach (dataInfo di in obj)
            {
                di.status_v = "Status: " + di.status_v;
                string barva;
                switch(di.barva)
                {
                    case "ZE": barva = "#FF32FF1D"; break;
                    case "CE": barva = "#FFFF1D1D"; break;
                    case "ZL": barva = "#FFF5FF1D"; break;
                    case "OR": barva = "#FFFFA31D"; break;
                    case "MO": barva = "#FF1D46FF"; break;
                    default: barva="x:Null"; break;
                }
                di.barva = barva;
                VypisZakazekli.Add(di);
            }

Zamezíš zbytečnému vytváření nové proměnné, dalším přiřazovacím operátorům a vytváření nového objektu v paměti.

Poté mě napadá ještě samotný list. Ten se v defaultním nastavením vytvoří jen pro určitý počet prvků, a když přidáš prvek, který se už do listu nevleze, tak se přealokuje (ber to s rezervou, není to realokace v pravém slova smyslu). Příklad: prázdný list může obsahovat 2 prvky. Jakmile se chceš přidat třetí prvek, list se přealokuje, aby mohl obsahovat 4 prvky. Jakmile chceš přidat pátý prvek, opět se přealokuje, aby mohl obsahovat třeba 8 prvků atd. Protože znáš počet prvků, které tam chceš uložit, můžeš toho využít a přímo Listu říct, kolik prvků bude obsahovat (nebude se několikrát volat ona "realokace"). Teď mě nenapadá, jaká je to funkce, zkus se podívat na Capacity property (nevím, jestli není read-only).

Víc mě teď nenapadá.

Editováno 25.9.2015 12:36
Nahoru Odpovědět 25.9.2015 12:35
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Odpovídá na patrik.valkovic
Matyáš Černohous (Matesak):

Díky, zkusím se na to podívat :) - u toho listu já sám nevím kolik tam těch položek bude, protože na začátku jsou ještě nějaké filtry, takže uživatel si může vyfiltrovat buď přímo tu jednu zakázku co hledá (ideální případ :D ) a nebo si klidně může zobrazit celou DB (cca 35 000 záznamů... to už aplikace spadne :D )

 
Nahoru Odpovědět 25.9.2015 12:44
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Matyáš Černohous (Matesak)
patrik.valkovic:

jasný, ale v obj už máš vracený počet objektů, které chce zobrazit.

VypisZakazekli.Capacity = obj.Count;

Nebo něco tomu podobné.

Nahoru Odpovědět 25.9.2015 12:51
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
vodslon
Člen
Avatar
Odpovídá na patrik.valkovic
vodslon:

Ahoj, když tady řešíte tento problém, napadlo mě zkoušel si někdy používat Parallel.ForEach ?

Já bych měl laickou představu, že díky tomu, že to umí pustit paralerně, tak to tu kolekci projede rychleji, ale podle hodinek to trvá naopak násobně krát déle, takže jsem to nikdy vlastně nepoužil nebo se to dá využít na něco jiného ?

 
Nahoru Odpovědět 25.9.2015 14:02
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na vodslon
patrik.valkovic:

Teď jen střílím od boku, ale mám za to, že třída Parallel je určená pro asynchronní metody. V principu nemůžeš tuhle operaci dělat paralelně, protože nevoláš žádnou asynchronní metodu. Abys dostal paralelní zpracováí - musely by se vytvořit vlákna, a to je operace náročná na CPU i na čas.

Nahoru Odpovědět 25.9.2015 14:06
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
vodslon
Člen
Avatar
Odpovídá na patrik.valkovic
vodslon:

No ty vlákna právě umí ten Parallel umí obsluhovat sám? Nebo já i když si to zkusím a udělám si nějakou kolekci List a udělám si Parallel.ForE­ach(List, a akce třeba jenom (x) => { a vypsat thread který to spracová něco jako Thread.Curren­tThread.Managed­ThreadId }

tak se mi ty čísla Threadů různí, takže to běží na více vláknech. Ovšem celkově pomaleji, než když to udělám klasicky foreach(var x in List){}.....

Píšu to, že se o tom něco chci dozvědět, takže vše co jsem napsal může být od A až do Z kravina, ale takhle jsem to pochopil.

 
Nahoru Odpovědět 25.9.2015 14:28
Avatar
patrik.valkovic
Šéfredaktor
Avatar
patrik.valkovic:

Ono si to asi vytváří vlákna samo, když tomu nepředáš task.

Představ si to takhle - asynchronní metody neblokují vlákno, protože operace probíhá na hardwaru (třeba harddisku). A na tuto operaci musíš počkat (třeba přečtení souboru). Parallel to vyřeší tak, že spustí první úlohu, a když dojde na asynchronní operaci (na kterou by musel čekat), tak mezi tím rozjede ten stejný cyklus ale s dalším objektem v pozadí. A opět, když tento druhý objekt narazí na asynchronní metodu, spustí cyklus pro třetí objekt atd atd. Jakmile je první asynchronní metoda dodělána, zastaví se právě prováděna operace a pokračuje se v prvním cyklu. Tak to funguje pro asynchronní metody.

Pokud nepředáš Task (tedy asynchronní volání), zřejmě si to vytvoří vlákna a rozloží to ty cykly mezi jednotlivé vlákna - jenže vytvoření vlákna je nákladná operace (která může trvat i 100ms - což není málo). Nevím, jak si parallel ty vlákna spravuje, jestli je ničí atd atd, ale je možné, že to bude pomalejší. Když použiješ uvnitř asynchronní metody, tak bude operace rozhodně rychlejší.

Nahoru Odpovědět 25.9.2015 14:33
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Odpovídá na Matyáš Černohous (Matesak)
sadlomaslox25:

problem bude podle me ve view vrstve. uz podle toho co vidim v kodu
case "MO": barva = "#FF1D46FF"; break;
default: barva="x:Null"; break;
podle me tam budou nejake silene konventory a cely kod brzdi jen tento radek
this.ListBox1­.ItemsSource = VypisZakazekli;
nehlede na to ze taky zalezi na typ kolekce v pozadi protoze jestli se jedna o observablecollec­tion ktera urcite zustava neustale prirazena na listbox tak pri pridani kazdeho itemu muze dochazet k prekresleni.

 
Nahoru Odpovědět  +1 25.9.2015 22:27
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 10.