1.04k likes | 1.16k Views
Programowanie równoległe Część 4 – własne wnioski. Jakub Binkowski. O mnie. Jakub Binkowski Senior .NET Developer @ Rule Financial Microsoft Most Valuable Professional (MVP) MCP, MCTS, MCPD Lider Łódzkiej Grupy Profesjonalistów IT & .NET jakub@binkowski.com.pl.
E N D
Programowanie równoległeCzęść 4 – własne wnioski Jakub Binkowski
O mnie • Jakub Binkowski • Senior .NET Developer @ Rule Financial • Microsoft Most Valuable Professional (MVP) • MCP, MCTS, MCPD • Lider Łódzkiej Grupy Profesjonalistów IT & .NET • jakub@binkowski.com.pl
Cykl „Programowanie równoległe w .NET” • Część IWielowątkowość w .NET 4.0 • Część IIInterakcja (synchronizacja) między wątkami, struktury danych i algorytmy równoległe • Część IIIOperacje asynchroniczne • Część IVDobre praktyki, najczęstsze błędy, testowanie
Agenda • Błędy • Dobre praktyki • Ogólne rady • Testowanie
Niepewne założenia var list = newList<int> {1, 3, 4, 5}; Co zwróci instrukcja: • list.Contains(5); wywołana jednocześnie z: • list.Insert(index: 1, item: 2); ?
Niepewne założenia • Czym jest List<T>? length = 4 items = 1 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Contains(5)? length = 4 items = 1 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Contains(5)? length = 4 items = FALSE 1 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Contains(5)? length = 4 items = FALSE 1 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Contains(5)? length = 4 items = FALSE 1 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Contains(5)? length = 4 items = TRUE 1 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Insert(index: 1, item: 2)? length = 4 items = 1 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Insert(index: 1, item: 2)? length = 4 items = 1 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Insert(index: 1, item: 2)? length = 4 items = 1 3 4 5 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Insert(index: 1, item: 2)? length = 4 items = 1 3 4 5 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Insert(index: 1, item: 2)? length = 4 items = 1 3 4 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Insert(index: 1, item: 2)? length = 4 items = 1 3 4 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Insert(index: 1, item: 2)? length = 4 items = 1 3 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Insert(index: 1, item: 2)? length = 4 items = 2 1 3 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Insert(index: 1, item: 2)? length = 4 items = 2 1 2 3 4 5 0 1 2 3 4
Niepewne założenia • Jak działa list.Insert(index: 1, item: 2)? length = 5 items = 1 2 3 4 5 0 1 2 3 4
Niepewne założeniaList.Insert(1,2) i List.Contains(5) razem length = 4 items = 5? FALSE 1 3 4 5 5 0 1 2 3 4
Niepewne założeniaList.Insert(1,2) i List.Contains(5) razem length = 4 items = 5? FALSE 1 3 4 4 5 0 1 2 3 4
Niepewne założeniaList.Insert(1,2) i List.Contains(5) razem length = 4 items = 5? FALSE 1 3 3 4 5 0 1 2 3 4
Niepewne założeniaList.Insert(1,2) i List.Contains(5) razem length = 4 items = 2 5? FALSE 1 2 3 4 5 0 1 2 3 4
Niepewne założeniaList.Insert(1,2) i List.Contains(5) razem length = 5 items = 1 2 3 4 5 0 1 2 3 4
Niepewne założeniaList.Insert(1,2) i List.Contains(5) razem length = 5 items = List.Contains(5) = false! 1 2 3 4 5 0 1 2 3 4
Dobra praktyka • Nie zakładaj, że jakieś 2 operacje są bezpieczne wielowątkowo • Synchronizuj jednoczesny dostęp: • lock (Monitor) • ReaderWriterLock(Slim) • itp. • Używaj kolekcji bezpiecznych wielowątkowo:System.Collections.Concurrent
Problem: Instrukcje (nie)atomowe jedna linia != jedna instukcja
Co się stało? • i++ to 3 instrukcje: • LOAD @i, R0 • INCREMENT R0 • STORE R0, @i
Co się stało? Pamięć: i = 5 Wątek 1 R0 = 0 i++ Wątek 2 R0 = 0 i++
Co się stało? Pamięć: i = 5 Wątek 1 R0 = 0 i++ Wątek 2 R0 = 0 i++
Co się stało? Pamięć: i = 5 Wątek 1 R0 = 0 i++: • LOAD @i, R0 Wątek 2 R0 = 0 i++: • LOAD @i, R0
Co się stało? Pamięć: i = 5 Wątek 1 R0 = 5 i++: • LOAD @i, R0 Wątek 2 R0 = 5 i++: • LOAD @i, R0
Co się stało? Pamięć: i = 5 Wątek 1 R0 = 6 i++: • LOAD @i, R0 • INC R0 Wątek 2 R0 = 5 i++: • LOAD @i, R0
Co się stało? Pamięć: i = 6 Wątek 1 R0 = 6 i++: • LOAD @i, R0 • INC R0 • STORE R0, @i Wątek 2 R0 = 5 i++: • LOAD @i, R0
Co się stało? Pamięć: i = 6 Wątek 1 R0 = 6 i++: • LOAD @i, R0 • INC R0 • STORE R0, @i Wątek 2 R0 = 6 i++: • LOAD @i, R0 • INC R0
Co się stało? Pamięć: i = 6 Wątek 1 R0 = 6 i++: • LOAD @i, R0 • INC R0 • STORE R0, @i Wątek 2 R0 = 6 i++: • LOAD @i, R0 • INC R0 • STORE R0, @i
Dobra praktyka • Nie zakładaj, że „jedna linia = jedna instrukcja” • Synchronizuj dostęp (lock, itp.) • Używaj gwarantowanych operacji atomowych, np.:Interlocked.Increment(ref_counter);
Zdarzenia (events) - przypomnienie • Deklaracja: publiceventEventHandlerSomethingHappened; • Wywołanie: if(SomethingHappened != null) SomethingHappened(this, EventArgs.Empty); • Subskrypcja: SomethingHappened += HandleSomethingHappened; SomethingHappened -= HandleSomethingHappened;
Problem: Zdarzenia a wielowątkowość Czy zdarzenia są bezpieczne wielowątkowo?
Co się stało? SomethingHappened = null Wątek 1 Wątek 2 SomethingHappened += HandleSomethingHappened;
Co się stało? SomethingHappened = HandleSomethingHappened Wątek 1 Wątek 2 SomethingHappened += HandleSomethingHappened;
Co się stało? SomethingHappened = HandleSomethingHappened Wątek 1 Wątek 2 SomethingHappened += HandleSomethingHappened; if (SomethingHappened != null)
Co się stało? SomethingHappened = HandleSomethingHappened Wątek 1 Wątek 2 SomethingHappened += HandleSomethingHappened; if (SomethingHappened != null) true
Co się stało? SomethingHappened = HandleSomethingHappened Wątek 1 Wątek 2 SomethingHappened += HandleSomethingHappened; SomethingHappened-= HandleSomethingHappened; if (SomethingHappened != null)
Co się stało? SomethingHappened = null Wątek 1 Wątek 2 SomethingHappened += HandleSomethingHappened; SomethingHappened-= HandleSomethingHappened; if (SomethingHappened != null)