35
PLINQ og Rx Enkel parallellprogrammering og nyskapende eventhåndtering BEKK Fagdag 20.11.2009 Åsmund Eldhuset

PLINQ og Rx

Embed Size (px)

DESCRIPTION

PLINQ og Rx. Enkel parallellprogrammering og nyskapende eventhåndtering. BEKK Fagdag 20.11.2009 Åsmund Eldhuset. Agenda. Del 1  PLINQ (Parallel LINQ) Del 2  Rx (Reactive Extensions) Del 3  Progging!. Del 1  PLINQ (Parallel LINQ). PLINQ (Parallel LINQ). - PowerPoint PPT Presentation

Citation preview

Page 1: PLINQ og Rx

PLINQ og Rx

Enkel parallellprogrammering og nyskapende eventhåndtering

BEKK Fagdag 20.11.2009

Åsmund Eldhuset

Page 2: PLINQ og Rx

Agenda

Del 1 PLINQ (Parallel LINQ)

Del 2 Rx (Reactive Extensions)

Del 3 Progging!

Page 3: PLINQ og Rx

Del 1 PLINQ (Parallel LINQ)

Page 4: PLINQ og Rx

PLINQ (Parallel LINQ)

En del av Parallel Extensions for .NET 4.0 (et stort rammeverk for parallellprogrammering)

Gir SQL-aktig adgang til metoder for parallell behandling av sekvenser og spørringer

Egner seg for problemer som har dataparallellisme (den samme operasjonen gjøres på mange dataelementer)

Egner seg ikke for problemer som har oppgaveparallellisme (flere forskjellige operasjoner gjøres samtidig) - det har man andre konstruksjoner i Parallel Extensions for

En del overhead; lønner seg bare for tunge beregninger

Page 5: PLINQ og Rx

AsParallel()

PLINQ er ekstremt enkelt i bruk: ta en eksisterende spørring og sett inn .AsParallel() etter datasettet

– Dette gir en IParallelQuery<T>, som implementerer IEnumerable<T> og har samme extension methods (Count(), ForAll(), GroupBy(), Sum(), Where() osv.)

Resten av spørringen ser ut som en vanlig LINQ-spørring

– Før: from i in data where i > 42 select 2 * i

– Etter: from i in data.AsParallel() where i > 42 select 2 * i

Kan også bruke funksjonssyntaksen:data.AsParallel().Where(i => i > 42).Select(i => 2 * i)

Merk: binære operatorer (f.eks. join / Join()) blir parallelle hvis og bare hvis den venstre datakilden er parallell

Page 6: PLINQ og Rx

Deklarativ parallellisme

SQL og LINQ er deklarative språk

– Man sier hva man vil ha i stedet for hvordan man vil at det skal skje

Siden man slipper å spesifisere implementasjonsdetaljene, åpner dette for:

– Automatisk optimalisering av treet som representerer uttrykket (alle kompilatorer og databasemotorer gjør dette)

– Reordering

– Common subexpression elimination

– Automatisk parallellisering

– Optimalisering kan foregå både statisk og runtime

Vi skal se litt på hva som skjer bak kulissene

Page 7: PLINQ og Rx

Lazy evaluation

Som i vanlig LINQ

– De fleste operatorer produserer ikke noe output før de blir bedt om det, og evaluerer ikke mer av inputen sin enn nødvendig

– Unntak: Sort() må evaluere hele inputen, og Join() må evaluere ett subtre

– Hvis du bare er ute etter sideeffektene av en spørring, tving gjennom evaluering ved f.eks. å kalle Last()

Page 8: PLINQ og Rx

Prosesseringstyper

Pipelined processing

– Én consumer-tråd, mange producer-tråder

– Brukes av de fleste operatorene

Stop-and-go processing

– Alle trådene er producers og bygger opp resultatlisten; deretter vil én tråd iterere over resultatene

– Brukes av ToList(), ToArray() og Sort()

Inverted enumeration

– (Inntil) én tråd per element som skal behandles

– Brukes av ForAll()

http://msdn.microsoft.com/en-us/magazine/cc163329.aspx

Page 9: PLINQ og Rx

Operatorparallellisme

Intraoperator / partisjonering

Interoperator / pipelining

Kombinering av disse

http://msdn.microsoft.com/en-us/magazine/cc163329.aspx

Thread 2

Thread 1

data

where p(x)

where p(x)

select f(x)

select f(x)

result

Thread 4Thread 3

Thread 2Thread 1

data

where p(x)

where p(x)

select f(x)

select f(x)

result

Thread 2Thread 1

data where p(x) select f(x) result

Page 10: PLINQ og Rx

Gotcha: Resultatrekkefølge

Rekkefølgen på resultatelementene er ikkedeterministisk (åpner for bedre parallellisering)

Legg på .AsOrdered() etter .AsParallel() for å tvinge resultatene til å stå i samme rekkefølge som inputelementene de stammer fra

Page 11: PLINQ og Rx

Gotcha: Exceptionhåndtering

Når en av PLINQ-trådene kaster en exception, dreper PLINQ alle trådene sine

– ...men før den rekker å gjøre det, har kanskje noen av de andre trådene også kastet exceptions

Dokumentasjonen påstår at uansett om én eller flere exceptions blir kastet, vil PLINQ pakke dem inn i en AggregateException, som har en InnerExceptions[]-property

– ...men så vidt jeg kan se, er det alltid den originale exceptionen som blir kastet

Uansett er det ofte best å håndtere exceptions inni predikatene, for å unngå at hele beregningen dør

Page 12: PLINQ og Rx

Gotcha: Feilbruk av delt minne

Data som ligger utenfor datasettet kan aksesseres av flere tråder samtidig race conditions

Feil (men trygt, om enn tåpelig, i vanlig LINQ):int count = 0;var res = from i in data.AsParallel() where i % 2 == 0 select count++;res.Last(); // Force evaluation

Riktig #1 (ekstern synkronisering):int count = 0;var res = from i in data.AsParallel() where i % 2 == 0select Interlocked.Increment(ref count);res.Last();

Riktig #2 (utnytt LINQ sine operatorer):int count = (from i in data.AsParallel() where i % 2 == 0 select i).Count();

Page 13: PLINQ og Rx

Del 2 Rx (Reactive Extensions)

Page 14: PLINQ og Rx

Rx (Reactive Extensions)

Lar oss se på en event som en kilde som produserer en sekvens av objekter

– Hvert objekt inneholder informasjon om én trigging av eventen

– Sekvensen kan vi manipulere ved hjelp av f.eks. LINQ

Gjør enkelte former for eventhåndtering og asynkron programmering mye lettere og mer elegant

Nettopp releaset; begrenset med dokumentasjon (men mange blogginnlegg...)

Page 15: PLINQ og Rx

Sekvensdiagram - IEnumerable<T> / IEnumerator<T>

Our thread

IEnumerator<T> IEnumerable<T>

GetEnumerator()

new

IEnumerator<T>

IEnumerator<T>

Current()

Get()

T

T

Page 16: PLINQ og Rx

Sekvensdiagram - IObservable<T> / IObserver<T>

Our thread

GUI thread

IObserver<T> IObservable<T>

new

Subscribe(IObserver<T>)

IDisposable

OnNext(T)

IObserver<T>

(call some method from the actual class of the IObservable<T>)

(trigger event and pass the T instance)

Page 17: PLINQ og Rx

IEnumerable<T> / IEnumerator<T>

interface IEnumerable<T> {IEnumerator<T> GetEnumerator();

}

interface IEnumerator<T> {T Current { get; } // Might throw exceptionbool MoveNext();

}

Page 18: PLINQ og Rx

Omskriving

La oss prøve å lage de "motsatte" interfacene, ved å bytte om på parametre og returverdier

interface IEnumerable<T> {IEnumerator<T> GetEnumerator();

}

interface IDualEnumerable<T> {void SetDualEnumerator(IDualEnumerator<T>);

}

interface IObservable<T> {IDisposable Subscribe(IObserver<T> observer);

}

Page 19: PLINQ og Rx

Omskriving

interface IEnumerator<T> {T Current { get; } // Might throw exceptionbool MoveNext();

} interface IDualEnumerator<T> {

T|Exception GetCurrent();bool MoveNext();

} interface IDualEnumerator<T> {

void SetCurrent(T|Exception);MoveNext(bool);

} interface IDualEnumerator<T> {

void SetCurrent(T);void SetException(Exception);MoveNext();

} interface IObserver<T> {

void OnNext(T value);void OnError(Exception exception);void OnCompleted();

}

Page 20: PLINQ og Rx

IObservable<T> / IObserver<T>

interface IObservable<T> {IDisposable Subscribe(IObserver<T> observer);

}

interface IObserver<T> {void OnCompleted();void OnError(Exception exception);void OnNext(T value);

}

Page 21: PLINQ og Rx

Hvordan lage observables

var obs = Observable.FromEvent<MouseEventArgs> (this, "MouseMove");

– Gir en IObservable<Event<MouseEventArgs>>

– LINQ behandler en IObservable<T> som en sekvens av T-instanser

var mouseMove = from mm in obs select new { mm.EventArgs.X, mm.EventArgs.Y };

– Gir en IObservable<'a>, hvor 'a er en new { int X, int Y }

Page 22: PLINQ og Rx

Registrering og avregistrering

Vi kan nå subscribe til vår IObservable:

– mouseMove.Subscribe(e => Console.WriteLine("{0}, {1}", e.X, e.Y));

– Subscribe() er en extension method som lar oss oppgi et lambdauttrykk som så vil bli pakket inn i en IObserver

Typisk unsubscriber man en annen plass enn der man subscriber, og da er ikke from-resultatet tilgjengelig lenger

Subscribe() returnerer en IDisposable

– Dispose() på denne vil unsubscribe

Page 23: PLINQ og Rx

Cross join av events

TODO

Page 24: PLINQ og Rx

"Extension events"

Syntaksen for å få tak i en IObservable for en event er strevsom

Bør innkapsles i extension methods

internal static class ExtensionMethods {public static

IObservable<IEvent<MouseEventArgs>> GetMouseMove(this Control control) {

return Observable.FromEvent<MouseEventArgs>

(control, "MouseMove");}

}

Har også en alternativ overload av FromEvent<>()

http://themechanicalbride.blogspot.com/2009/07/developing-with-rx-part-1-extension.html

Page 25: PLINQ og Rx

Timing

a.Until(b) spesifiserer at man bare er interessert i events fra a inntil det kommer en event fra b

– Gjør det enkelt å kansellere subscriptions når visse hendelser inntreffer

a.Delay(t)

– Venter i t millisekunder med å videresende events fra a

Observable.Return(x)

– Lager en sekvens med bare ett element: x

from a in eventAfrom b in Observable.Return(new Unit()) .Delay(1000).Until(eventB)select a

– Hver gang eventA utløses, vil vi få vite om den ett sekund senere - med mindre eventB utløses i mellomtiden

– (Unit er en slags void-verdi)

Page 26: PLINQ og Rx

Kombinering av events

0 1 2

0 1

3 4

2

0 1 2

012 3 4

0 1 2 0 13 42

a

b

a.Merge(b)

a.Until(b)

a.WaitUntil(b)

a.Zip(b, func) 0 1 2

Page 27: PLINQ og Rx

Asynkron programmering

Observable.ToAsync() lager en asynkron utgave av en funksjon

– Når den resulterende funksjonen kalles, får man en IObservable som produserer resultater når funksjonen blir ferdig

var sqrt = Observable.ToAsync<int, double> ((number) => Math.Sqrt(number));

from s in sqrt(42) ... Hvis koden som abonnerer på den asynkrone funksjonen skal

røre GUI'et, må du kalle s.SubscribeOnWindowsForms(this).Subscribe(...)

Page 28: PLINQ og Rx

Del 3 Progging!

Page 29: PLINQ og Rx

Installasjon

Rx for VS2008: http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx

– Prosjekter trenger referanse til System.Reactive og System.CoreEx

Parallel Extensions for VS2008: http://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3

– Prosjekter trenger referanse til System.Threading

Den utleverte koden og LF'ene kan sjekkes ut anonymt over SVN:svn co http://linqkurs.googlecode.com/svn/trunk/ linq

Page 30: PLINQ og Rx

Rx: Oppgave 1 - Drag-and-drop

En drag-and-drop-operasjon består av følgende sekvens av events:

1. En MouseDown

2. Vilkårlig mange MouseMove

3. En MouseUp

Vi ønsker å abonnere på eventen "musebevegelse mens en drag-and-drop fopegår"

Bruk cross join og en passende extension method for å kombinere disse event-strømmene

...og gjør noe interessant (f.eks. tegne et punkt på skjermen) for hver slik musebevegelse

http://mnajder.blogspot.com/2009/08/and-drop-with-reactive-framework.html

Page 31: PLINQ og Rx

Rx: Oppgave 2 - Autocompletion

TODO

http://mnajder.blogspot.com/2009/08/incremental-find-with-reactive.html

Page 32: PLINQ og Rx

PLINQ: Oppgave 1 - Mandelbrotfraktal

Se prosjektet Part4_Plinq

Page 35: PLINQ og Rx

BEKK CONSULTING ASSKUR 39, VIPPETANGEN. P.O. BOX 134 SENTRUM, 0102 OSLO, NORWAY.

WWW.BEKK.NO

Åsmund EldhusetKonsulent, Avdeling Trondheim

959 39 [email protected]