Avatar billede CodingJoe Nybegynder
04. maj 2013 - 20:18 Der er 12 kommentarer og
2 løsninger

Threading Task forståelse

Hejsa

Jeg er i denne weekend ved at prøve at erobre threading delen i .Net frameworket.

Jeg undrer / spekulerer mig over, hvordan det fungerer.

Jeg har fx. lavet tre metoder:

Som jeg bruger til at udfylde data i et hovedobjekt.
// Hovedobjekt
Person p = new Person();

public List<Interesse> HentPersonInteresser()
{
...
...
...
return interesser;
}

public List<Sprog> HentPersonSprog()
{
...
// lagt en forsinkelse ind i 10 sek. For at simulere en lang somoperation
...
return sprog;
}

public List<Aktivitet> HentPersonAktiviteter()
{
...
...
return aktiviteter;
}

Herefter samler jeg kaldene ved at definere tre tasks
var interesser = Task<List<Interesse>>.Factory.StartNew(() => MinStatiskeKlasse.HentPersonInteresser());
var sprog = Task<List<Sprog>>.Factory.StartNew(() => MinStatiskeKlasse.HentPersonSprog());
var aktiviteter = Task<List<Aktivitet>>.Factory.StartNew(() => MinStatiskeKlasse.HentPersonAktiviteter());

p.Interesser = interesser.Result;
p.Sprog = sprog.Result;
p.Aktiviteter = aktiviteter.Result;


Jeg prøver at debugge mig igennem og bruger faktisk også parallel watch på p.Interesser, p.Sprog og p.Aktiviteter, men jeg kan ikke se at aktiviteter bliver afsluttet / populeret før sprog, som jeg jo har lagt imellem med en forsinkelse i.

Kan jeg være sikker på at ovenstående giver mig tre separate tråde, der arbejder isoleret og ikke afventer på hinanden sekventielt?

Jeg vil jo forvente at min tredje metode, fylder p.Aktiviteter op før p.Sprog.

Er ovenstående korrekt, ifht. den multitråde tilgang og performance optimering, jeg prøver at opnå?

Jeg er åben for forslag og andre måder at løse min performance optimeringstrang på...
Avatar billede Syska Mester
04. maj 2013 - 22:15 #1
Problemet er: interesser.Result

Jeg er rimelig sikker på den laver en lock og venter på at resultatet er klart.

Du skal nok bruge:
http://msdn.microsoft.com/DA-DK/library/dd270695.aspx

Kun et gæt, som jeg dog er rimelig sikker på vil få det til at virke. Men prøv det og vend tilbage.

mvh
Avatar billede Syska Mester
04. maj 2013 - 22:18 #2
http://msdn.microsoft.com/DA-DK/library/dd321468.aspx

The get accessor for this property ensures that the asynchronous operation is complete before returning. Once the result of the computation is available, it is stored and will be returned immediately on later calls to Result.
Avatar billede Syska Mester
04. maj 2013 - 22:18 #3
svar.

Da jeg antager jeg nu har fundet det rigtige svar.
Avatar billede CodingJoe Nybegynder
04. maj 2013 - 22:46 #4
Jeg må lige være en smule mere klar i udmeldingen...det er ikke fordi, der er noget, der ikke virker.

Det drejer om min antagelse om, at mine tre metoder går i gang i hver tråd, uden at den ene venter på den anden.

Jeg har et scenarie, hvor jeg skal indhente data fra et sted mellem 5-8 metoder, og her vil jeg naturligvis kalde dem tråd baseret, så de kan starte op parallelt og på den måde spare tid.
Dvs. den metode, der tager længst tid at indhente data, bliver den tid hele processen tager.

Jeg accepterer ikke svar baseret på gæt - desværre.
Med mindre du og andre herinde mener, at min kode herinde er helt ok for at opnå mine optimeringer.
Avatar billede Syska Mester
04. maj 2013 - 23:00 #5
Ja, hvis du har 1000 metoder og nummer 1 tager 1 sek og 2 tager 2 sek etc..... og metode 1000 tage 1000 sek.

Men det vil køre Parrellelt ...

At det så nok ikke er helt optimalt at starte 1000 tråde der alle "i pricippet vil tager 100% af dine CPU er en helt anden ting.

Men de vil køre parrellelt.

Du skriver:
"Jeg vil jo forvente at min tredje metode, fylder p.Aktiviteter op før p.Sprog."

og

"Jeg prøver at debugge mig igennem og bruger faktisk også parallel watch på p.Interesser, p.Sprog og p.Aktiviteter, men jeg kan ikke se at aktiviteter bliver afsluttet / populeret før sprog, som jeg jo har lagt imellem med en forsinkelse i."

Og netop lige der passer mit svar ind ... NEJ, De vil køre parrellelt, da den venter på første metode bliver færdig.

Da du kalder:
p.Interesser = interesser.Result;
p.Sprog = sprog.Result;
p.Aktiviteter = aktiviteter.Result;

Og som andet link beskriver:
The get accessor for this property ensures that the asynchronous operation is complete before returning. Once the result of the computation is available, it is stored and will be returned immediately on later calls to Result.

Ergo ... din antagelse er forkert, med mindre du laver om i din kode.

Jeg ville jo nok vente på alle tråde ... da A måske er afhængig af B og C ... eller modsat. Du skal jo på et eller andet tidspunkt vide hvor eller hvis dine tråde overhovedet bliver færdige.

Håber det var nok forklaring.
Avatar billede CodingJoe Nybegynder
04. maj 2013 - 23:19 #6
Aha - Så returnering vil kun foregå, hvis den foregående metode / tråd er færdig og har et retur svar. Hvad hvis det er en void.

Sidenote: I TPL - Task - PLINQ, så er der i frameworket allokeret 20 tråde i threadpool, som jeg gør brug af i dette tilfælde. Disse skulle være en del af de features i framework 4.0 og opefter. Med mindre det er for overdrivelsens skyld, du nævner 1000 tråde, så er analogien med de 1000 tråde i dette indlæg forkert indsat.
Håber det ikke giver anledning for andre at misforstå, at man kan gå tråd-amok på ens CPU.

Jeg afventer indlæg fra andre, inden jeg uddeler points.
Jeg vil gerne have andre perspektiver.
Avatar billede Syska Mester
04. maj 2013 - 23:31 #7
Så ville du selvfølgelig ikke kunne kalde .Result :-)

Og så skal du nok bruge en af de andre metoder på Task til at vente og se om den bliver færdig :-)

Ja, der er 20 tråde ligesom den ThreadingPool/List something som jeg aldrig har brugt.

Men derfor kan den stadig overrides og derfor mener jeg stadig det er valid. Hvis man gør det ... så er det ens eget ansvar.

Helt fint ... det er et åbenbart forum.

Jeg har bare svaret på det jeg mente var et spøgsmål. Den assignment burde du nok have med ind i din metode hvis du vil have "p.EnAfDeTreProperties" assigned så snart kaldet er færdigt. Dette kan jo nemt gøres med en Action.

Men udover det, så er tilgangen rigtig ... du får jo kørt dem på samme tid ... at assignment af de 3 properties sker parrellelt senere er jo kun godt. Så er du tilbage i din single thread igen og du har løst et perf problem, f.eks hvis du venter på langsomme webservices eller andre ting.
Avatar billede CodingJoe Nybegynder
04. maj 2013 - 23:40 #8
Jeps, der er kald i underliggende databaser samt services...

Jeg har i BizTalk gjort det ved at lave parallelle orkestreringer, i dette rene c# kode, forsøger jeg at opnå det samme ved parallelle tråde...
Avatar billede Syska Mester
04. maj 2013 - 23:51 #9
Yes. Så er det i hvert fald den rigtige vej.

Vi havde en metode der læste 400 forskellige filer fra et file share. Gik fra 12 sek til 1-2 sek. Nam nam nam :-)

Så det kan bestemt godt betale sig ...

Men nu vil jeg lade andre kommer til. Jeg har indtil videre ikke rigtig mere at bidrage med udover TPL er nice.
Avatar billede arne_v Ekspert
05. maj 2013 - 01:36 #10
Umiddelbart synes jeg at din originale kode ser helt fin ud.

Du starter N task som koerer parallelt og derefter venter du paa at alle task er faerdige.

Hvis taskene tager bare en lidt tid at udfoere vil de koere i separate traade (indtil antal task overstiger antal traade i pool).

Hvilke .Result der faktisk kommer til at vente afhaenger af raekkefoelgen du kalder og den tid de forskellige task tager.

Men den samlede tid inden alle .Result har returneret og dermed alle task faerdige er den samme uanset raekkefoelgen du kalder i.
Avatar billede arne_v Ekspert
05. maj 2013 - 01:57 #11
Illustration:


using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace E
{
    public class Program
    {
        private static string Any(int secs)
        {
            Thread.Sleep(secs * 1000);
            return Thread.CurrentThread.ManagedThreadId.ToString();
        }
        public static string One()
        {
            return Any(1);
        }
        public static string Two()
        {
            return Any(2);
        }
        public static string Three()
        {
            return Any(3);
        }
        public static void Test123()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Task<string> one = Task<string>.Factory.StartNew(() => One());
            Task<string> two = Task<string>.Factory.StartNew(() => Two());
            Task<string> three = Task<string>.Factory.StartNew(() => Three());
            string oneres = one.Result;
            Console.WriteLine("One result in {0} ms in thread {1}", sw.ElapsedMilliseconds, oneres);
            string twores = two.Result;
            Console.WriteLine("Two result in {0} ms in thread {1}", sw.ElapsedMilliseconds, twores);
            string threeres = three.Result;
            Console.WriteLine("Three result in {0} ms in thread {1}", sw.ElapsedMilliseconds, threeres);
            Console.WriteLine("All result in {0} ms", sw.ElapsedMilliseconds);
        }
        public static void Test321()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Task<string> one = Task<string>.Factory.StartNew(() => One());
            Task<string> two = Task<string>.Factory.StartNew(() => Two());
            Task<string> three = Task<string>.Factory.StartNew(() => Three());
            string threeres = three.Result;
            Console.WriteLine("Three result in {0} ms in thread {1}", sw.ElapsedMilliseconds, threeres);
            string twores = two.Result;
            Console.WriteLine("Two result in {0} ms in thread {1}", sw.ElapsedMilliseconds, twores);
            string oneres = one.Result;
            Console.WriteLine("One result in {0} ms in thread {1}", sw.ElapsedMilliseconds, oneres);
            Console.WriteLine("All result in {0} ms", sw.ElapsedMilliseconds);
        }
        public static void Test213()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Task<string> one = Task<string>.Factory.StartNew(() => One());
            Task<string> two = Task<string>.Factory.StartNew(() => Two());
            Task<string> three = Task<string>.Factory.StartNew(() => Three());
            string twores = two.Result;
            Console.WriteLine("Two result in {0} ms in thread {1}", sw.ElapsedMilliseconds, twores);
            string oneres = one.Result;
            Console.WriteLine("One result in {0} ms in thread {1}", sw.ElapsedMilliseconds, oneres);
            string threeres = three.Result;
            Console.WriteLine("Three result in {0} ms in thread {1}", sw.ElapsedMilliseconds, threeres);
            Console.WriteLine("All result in {0} ms", sw.ElapsedMilliseconds);
        }
        public static void Main(string[] args)
        {
            Test123();
            Test321();
            Test213();
            Console.ReadKey();
        }
    }
}
Avatar billede CodingJoe Nybegynder
05. maj 2013 - 18:32 #12
Tak Arne

Dine forklaringer er i en klasse for sig selv :)

Jeg prøver det lige og melder tilbage inden længe...
Avatar billede CodingJoe Nybegynder
08. maj 2013 - 19:00 #13
Hej Arne

Så fik jeg prøvet det, og det ser rigtigt fint ud.

Jeg vil gerne fordele mine points, så smid lige et svar ind her, så sørger jeg for at fordele pointene.
Avatar billede arne_v Ekspert
08. maj 2013 - 19:12 #14
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester