Bezbolesne Programowanie Współbieżne



Podobne dokumenty
Zaawansowany kurs języka Python

Wątki i komunikacja między nimi w języku Python

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Kurs rozszerzony języka Python

Java. Wykład. Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

Programowanie w Sieci Internet. Python: Wątki. Kraków, 12 grudnia 2014 r. mgr Piotr Rytko Wydział Matematyki i Informatyki

Wątki. Definiowanie wątków jako klas potomnych Thread. Nadpisanie metody run().

Java. Programowanie Obiektowe Mateusz Cicheński

Programowanie obiektowe

Kurs języka Python. Wątki

WSPÓŁBIEŻNOŚĆ. MATERIAŁY:

Plan. krótkie opisy modułów. 1 Uwagi na temat wydajności CPython a. 2 Podstawowe techniki poprawiające wydajność obliczeniową

Języki i Techniki Programowania II. Wykład 7. Współbieżność 1

Wykład 2 Wybrane konstrukcje obiektowych języków programowania (1)

Installation of EuroCert software for qualified electronic signature

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Metody Metody, parametry, zwracanie wartości

Zaawansowany kurs języka Python

Wykład 12. Programowanie serwera MS SQL 2005 w C#

Programowanie komputerów

Programowanie współbieżne Laboratorium nr 11

Zaawansowane aplikacje WWW - laboratorium

Programowanie współbieżne Zadanie 5 - Podstawowe problemy programowania współbieżnego

Technologie cyfrowe semestr letni 2018/2019

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

Programowanie funkcyjne w Pythonie

Wstęp. Przetwarzanie współbieżne, równoległe i rozproszone

Przegląd języka Python. Łukasz Anwajler

Współbieżność w środowisku Java

Operatory. Składnia. Typy proste. Znaki specjalne

Pętle while, for, do while, instrukcje break, continue, switch 1. Pętle

Serwer współbieżny połączeniowy

Programowanie w języku Java. Bazy danych SQLite w Javie

Wzorce logiki dziedziny

Obliczenia równoległe i rozproszone w JAVIE. Michał Kozłowski 30 listopada 2003

WIELOWĄTKOWOŚĆ. Waldemar Korłub. Platformy Technologiczne KASK ETI Politechnika Gdańska

Modelowanie numeryczne w fizyce atmosfery Ćwiczenia 3

Java Programowanie Obiektowe Ćwiczenie 1- wprowadzenie

Języki Programowania II Wykład 3. Java podstawy. Przypomnienie

Zofia Kruczkiewicz, Programowanie obiektowe - java, wykład 2 1

Signals + Threads: Qt vs. Boost

Kurs programowania. Wykład 9. Wojciech Macyna

Java: interfejsy i klasy wewnętrzne

Programowanie obiektowe

Systemy Rozproszone - Ćwiczenie 6

Programowanie obiektowe

Aplikacja wielowątkowa prosty komunikator

Podstawy współbieżności

Podstawy Programowania ELEMENTY PROGRAMU i TYPY DANYCH

Aplikacje w Javie- wykład 11 Wątki-podstawy

Projektowanie algorytmów rekurencyjnych

Programowanie obiektowe i zdarzeniowe

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Model pamięci. Rafał Skinderowicz

Machine Learning for Data Science (CS4786) Lecture11. Random Projections & Canonical Correlation Analysis

Wstęp do ruby dla programistów javy

Kurs programowania. Wykład 13. Wojciech Macyna. 14 czerwiec 2017

Programowanie i projektowanie obiektowe

Dokumentacja do API Javy.


Programowanie w języku Java. Kolekcje

Komponenty sterowane komunikatami

1. Co można powiedzieć o poniższym kodzie (zakładając, że zaimportowano wszystkie niezbędne klasy)?

Wykład 4: Klasy i Metody

Podstawy programowania obiektowego

Testy jednostkowe - zastosowanie oprogramowania JUNIT 4.0 Zofia Kruczkiewicz

Algorytmy z powrotami. Algorytm minimax

Jak ujarzmić hydrę czyli programowanie równoległe w Javie. dr hab. Piotr Bała, prof. UW ICM Uniwersytet Warszawski

Przetwarzanie wielowątkowe przetwarzanie współbieżne. Krzysztof Banaś Obliczenia równoległe 1

Język Java wątki (streszczenie)

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Wieloplatformowe aplikacje sieciowe. dr inż. Juliusz Mikoda mgr inż. Anna Wawszczak

DODATKOWE ĆWICZENIA EGZAMINACYJNE

Programowanie obiektowe

Technologie cyfrowe semestr letni 2018/2019

Języki i metody programowania Java INF302W Wykład 2 (część 1)

Przetwarzanie równoległe i współbieżne

Wstęp. Ale po co? Implementacja

Automatyczne generowanie testów z modeli. Bogdan Bereza Automatyczne generowanie testów z modeli

Języki i metody programowania Java Obsługa zdarzeń - przykłady

Pierwsza ramka. dr Anna Łazińska, WMiI UŁ Podstawy języka Java 1 / 10

Python. Wprowadzenie. Jolanta Bachan

Wzorce dystrybucji i wspólbieżności autonomicznej

Podstawy programowania w Pythonie

Wykorzystywanie parsera DOM w programach Java i PL/SQL

Dzi kuj za uwag! Spotkania z Pythonem. Cz ± 1 - podstawy - rozwi zania zada« Michaª Alichniewicz. Gda«sk Studenckie Koªo Automatyków SKALP

(Apache) CouchDB. Krzysztof Kulewski 2008

SWING c.d. przydatne narzędzia: JFileChooser, JOptionPane. drag'n drop, menu kontekstowe.


Języki i metody programowania Java Lab1 Zofia Kruczkiewicz

Przykład -

Generatory. Michał R. Przybyłek

Programowanie Komputerów

dziedziczenie - po nazwie klasy wystąpią słowa: extends nazwa_superklasy

Programowanie i projektowanie obiektowe

model isinga 2d ab 10 grudnia 2016

Dzisiejszy wykład. Wzorce projektowe. Visitor Client-Server Factory Singleton

Wielowątkowość. Programowanie w środowisku rozproszonym. Wykład 1.

Machine Learning for Data Science (CS4786) Lecture 11. Spectral Embedding + Clustering

Stanowe komponenty sesyjne

Transkrypt:

Bezbolesne Programowanie Współbieżne Konrad Siek 26 III 2014

Lata 90-te???

Częstotliwość procesorów Tranzystory 0 500 1000 1500 1985 1990 1995 2000 Rok

Lata 90-te My new computer s got the clocks, it rocks, but it was obsolete before I opened the box. You say you ve had your desktop for over a week? Throw that junk away, man, it s an antique. Your laptop is a month old? Well, that s great. If you could use a nice, heavy paperweight... It s all about the Pentiums, Weird Al, 1999

Częstotliwość procesorów Taktowanie [MHz] 0 1000 3000 1985 1990 1995 2000 2005 2010 Rok

Prawo Moore-a in action Tranzystory 0.0e+00 1.5e+09 1985 1990 1995 2000 2005 2010 Rok

Liczby rdzeni w procesorach Rdzenie 2 4 6 8 10 1985 1990 1995 2000 2005 2010 Rok

Od rdzeni Współbieżność

Od rdzeni Współbieżność... ale współbieżność boli

... boli?

Rzeczy których nie lubie Szukanie bugów (bagów?) Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie problemów synchronizacji

Rzeczy których nie lubie Szukanie bugów (bagów?) Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie problemów synchronizacji

Rzeczy których nie lubie Szukanie Heisenbugów Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie problemów synchronizacji

Heisenbug

Rzeczy których nie lubie Szukanie Heisenbugów Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie problemów synchronizacji

Rzeczy których nie lubie Szukanie Heisenbugów Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie problemów synchronizacji

Wrzucanie kodu strukturalnego do funkcjonalnego class Elem: def init (self, transaction, t, next): self.transaction = transaction self.t = t self.next = next _head = None def insert(transaction, t): if _head is None: _head = Elem(transaction, t, None) return elem = _head while True: if elem.t <= t: temp = Elem(elem.transaction, elem.t, elem.next) elem.transaction = transaction elem.t = t elem.next = temp return else: if elem.next: elem = elem.next else: elem.next = Elem(transaction, t, None) return

Wrzucanie kodu strukturalnego do funkcjonalnego from threading import RLock, Condition class Elem: def init (self, transaction, t, next): self.transaction = transaction self.t = t self.next = next _head = None _global_lock = Condition() _transaction_lock = RLock() def insert(head, transaction, t): elem = head while True: if elem.t <= t: temp = Elem(elem.transaction, elem.t, elem.next) elem.transaction = transaction elem.t = t elem.next = temp return else: if elem.next: elem = elem.next else: elem.next = Elem(transaction, t, None) return

Wrzucanie kodu strukturalnego do funkcjonalnego from threading import RLock, Condition class Elem: def init (self, transaction, t, next): self.transaction = transaction self.t = t self.next = next _head = None _global_lock = Condition() _transaction_lock = RLock() def insert(head, transaction, t): elem = head while True: if elem.t <= t: temp = Elem(elem.transaction, elem.t, elem.next) elem.transaction = transaction elem.t = t elem.next = temp return else: if elem.next: elem = elem.next else: elem.next = Elem(transaction, t, None) return def lock(transaction, length): _global_lock.acquire() if _head is None: acquired = _transaction_lock.acquire(blocking=false) if acquired and _head is None: _global_lock.release() return else: if _head == null: _head = Elem(T, t, null) else: insert(_head, T, t) while True: _global_lock.wait() if _head.t = T: _transaction_lock.acquire() if _head is not None: _head = _head.next _global_lock.release() return else: _global_lock.notify() def unlock(): _global_lock.acquire() _transaction_lock.release() _global_lock.notify() _global_lock.release() return

Rzeczy których nie lubie Szukanie Heisenbugów Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie problemów synchronizacji

Rzeczy których nie lubie Szukanie Heisenbugów Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie problemów synchronizacji

Rozwiązywanie problemów synchronizacji

Rozwiązywanie problemów synchronizacji

Rzeczy których nie lubie Szukanie Heisenbugów Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie problemów synchronizacji

Rzeczy których nie lubie Szukanie Heisenbugów Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie 2 problemów jednocześnie

Rozwiązania których szukam Szukanie Heisenbugów Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie 2 problemów jednocześnie

Rozwiązania których szukam Szukanie Heisenbugów Wrzucanie kodu strukturalnego do funkcjonalnego Rozwiązywanie 2 problemów jednocześnie Uniwersalne

Rozwiązania którzych szukam Szukanie Heisenbugów Wrzucanie kodu strukturalnego do funkcjonalnego Proste w implementacji Rozwiązywanie 2 problemów jednocześnie Uniwersalne

Rozwiązania których szukam Szukanie Heisenbugów Bezbłędne Wrzucanie kodu strukturalnego do funkcjonalnego Proste w implementacji Rozwiązywanie 2 problemów jednocześnie Uniwersalne

Rozwiązania których szukam Szukanie Heisenbugów Bezbłędne Wrzucanie kodu strukturalnego do funkcjonalnego Proste w implementacji Rozwiązywanie 2 problemów jednocześnie Uniwersalne Wydajne

Rozwiązania

Globalny zamek from threading import Thread, Lock _global_lock = Lock() _shared_data = [0, 0, 0, 0] class GLThread (Thread): def init (self, data, index): Thread. init (self) self.index = index self.data = data def run(self): with _global_lock: self.data[self.index] += 1 my_data = self.data[self.index] print( set, self.index, to, my_data) for i in range(0, 10): GLThread(_shared_data, i % len(_shared_data)).start()

Globalny zamek from threading import Thread, Lock _global_lock = Lock() _shared_data = [0, 0, 0, 0] class GLThread (Thread): def init (self, data, index): Thread. init (self) self.index = index self.data = data def run(self): with _global_lock: self.data[self.index] += 1 my_data = self.data[self.index] print( set, self.index, to, my_data) for i in range(0, 10): GLThread(_shared_data, i % len(_shared_data)).start()

Globalny zamek Bezbolesna współbieżność

Globalny zamek Bezbolesna współbieżność

Globalny zamek Bezbolesna współbieżność

Wątki funkcyjne

Duplikaty

Duplikaty from hashlib import md5 hashes = [None] * len(files) def make_hash(i): source = open(files[i], rb ) data = source.read() source.close() hashes[i] = md5(data).digest() for i in range(0, len(files)): make_hash(i)

Duplikat from hashlib import md5 from _thread import start_new_thread # python2: thread hashes = [None] * len(files) def make_hash(i): source = open(files[i], rb ) data = source.read() source.close() hashes[i] = md5(data).digest() for i in range(0, len(files)): start_new_thread(function=make_hash, args=(i,))

Duplikat from hashlib import md5 from _thread import start_new_thread # python2: thread hashes = [None] * len(files) def make_hash(i): source = open(files[i], rb ) data = source.read() source.close() hashes[i] = md5(data).digest() for i in range(0, len(files)): start_new_thread(function=make_hash, args=(i,))

Global Interpreter Lock A global interpreter lock (GIL) is used internally to ensure that only one thread runs in the Python VM at a time. In general, Python offers to switch among threads only between bytecode instructions; how frequently it switches can be set via sys.setswitchinterval(). Each bytecode instruction and therefore all the C implementation code reached from each instruction is therefore atomic from the point of view of a Python program. http://docs.python.org/3.3/library/multiprocessing.html

Duplikaty from hashlib import md5 #from _thread import start_new_thread # python2: thread from multiprocessing import Process hashes = [None] * len(files) def make_hash(i): source = open(files[i], rb ) data = source.read() source.close() hashes[i] = md5(data).digest() for i in range(0, len(files)): #start_new_thread(function=make_hash, args=(i,)) Process(target=make_hash, args=(i,)).start()

Duplikaty from hashlib import md5 from multiprocessing import Process hashes = [None] * len(files) def make_hash(i): source = open(files[i], rb ) data = source.read() source.close() hashes[i] = md5(data).digest() for i in range(0, len(files)): Process(target=make_hash, args=(i,)).start()

Duplikaty

Duplikaty

Duplikaty from hashlib import md5 from multiprocessing import Process hashes = [None] * len(files) def make_hash(i): source = open(files[i], rb ) data = source.read() source.close() hashes[i] = md5(data).digest() for i in range(0, len(files)): Process(target=make_hash, args=(i,)).start()

Duplikaty from hashlib import md5 from multiprocessing import Pool hashes = [None] * len(files) def make_hash(i): with semaphore: source = open(files[i], rb ) data = source.read() source.close() hashes[i] = md5(data).digest() pool = Pool(processes=4) # define after make_hash for i in range(0, len(files)): pool.apply_async(func=make_hash, args=(i,))

Duplikaty from hashlib import md5 from multiprocessing import Pool hashes = [None] * len(files) def make_hash(i): source = open(files[i], rb ) data = source.read() source.close() hashes[i] = md5(data).digest() pool = Pool(processes=4) # define after make_hash for i in range(0, len(files)): pool.apply_async(func=make_hash, args=(i,)) pool.close() # close before joining pool.join()

Wątki funkcyjne Preferują solipsyzm

Wątki funkcyjne Preferują solipsyzm tylko odczyt bez konfliktów

Wątki funkcyjne Preferują solipsyzm tylko odczyt bez konfliktów Niski koszt

Wątki funkcyjne Preferują solipsyzm tylko odczyt bez konfliktów Niski koszt ten sam schemat <10 lini kodu

Wątki funkcyjne Preferują solipsyzm tylko odczyt bez konfliktów Niski koszt ten sam schemat <10 lini kodu Znaczna poprawa efektywności

Wątki funkcyjne (Python) from hashlib import md5 from multiprocessing import Pool hashes = [None] * len(files) def make_hash(i): source = open(files[i], rb ) data = source.read() source.close() hashes[i] = md5(data).digest() pool = Pool(processes=4) # define after make_hash for i in range(0, len(files)): pool.apply_async(func=make_hash, args=(i,)) pool.close() # close before joining pool.join()

Wątki funkcyjne (Python) map from hashlib import md5 from multiprocessing import Pool hashes = [None] * len(files) def make_hash(i): source = open(files[i], rb ) data = source.read() source.close() hashes[i] = md5(data).digest() pool = Pool(processes=4) # define after make_hash pool.map(func=make_hash, iterable=range(0, len(files)))

Pamięć transakcyjna

Pamięć transakcyjna

Pamięć transakcyjna

Pamięć transakcyjna

Pamięć transakcyjna

Pamięć transakcyjna

Pamięć transakcyjna

Pamięć transakcyjna

Pamięć transakcyjna

Pamięć transakcyjna

Pamięć transakcyjna Python: Kamaelia/Axon (www.kamaelia.org) Durus (www.mems-exchange.org/software/durusworks/) Java Deuce STM (www.deucestm.org) C SXM (research.microsoft.com) C/C++ wbudowana w GCC (gcc.gnu.org/wiki/transactionalmemory)

Bank

Bank ACCOUNTS = 10 TRANSFERS = 10 ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {}

Bank ACCOUNTS = 10 TRANSFERS = 10 ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def init(ids, sum): for i in ids: accounts[i] = sum def total(ids): total = 0 for i in ids: total += accounts[i] return total def transfer(a, b, sum): accounts[a] -= sum accounts[b] += sum

Bank from random import choice, randint ACCOUNTS = 10 TRANSFERS = 10 ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def init(ids, sum): for i in ids: accounts[i] = sum init(ids, 1000) for i in range(0, TRANSFERS): a = choice(ids) b = choice(filter(lambda x: x!= a, ids)) sum = randint(1, 5) * 100 transfer(a, b, sum) print total(ids) def total(ids): total = 0 for i in ids: total += accounts[i] return total def transfer(a, b, sum): accounts[a] -= sum accounts[b] += sum

Bank from random import choice, randint ACCOUNTS = 10 TRANSFERS = 10 ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def init(ids, sum): # transaction start for i in ids: accounts[i] = sum # transaction end init(ids, 1000) for i in range(0, TRANSFERS): a = choice(ids) b = choice(filter(lambda x: x!= a, ids)) sum = randint(1, 5) * 100 # fork process transfer(a, b, sum) # join processes print total(ids) def total(ids): # transaction start total = 0 for i in ids: total += accounts[i] # transaction end return total def transfer(a, b, sum): # transaction start accounts[a] -= sum accounts[b] += sum # transaction end

Bank from random import choice, randint from multiprocessing import Pool ACCOUNTS = 10 TRANSFERS = 10 ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def init(ids, sum): # transaction start for i in ids: accounts[i] = sum # transaction end init(ids, 1000) for i in range(0, TRANSFERS): a = choice(ids) b = choice(filter(lambda x: x!= a, ids)) sum = randint(1, 5) * 100 pool.apply_async(func=transfer, args=(a,b,sum)) pool.close() pool.join() print total(ids) def total(ids): # transaction start total = 0 for i in ids: total += accounts[i] # transaction end return total def transfer(a, b, sum): # transaction start accounts[a] -= sum accounts[b] += sum # transaction end

Bank from random import choice, randint from multiprocessing import Pool from durus.connection import Connection from durus.client_storage import ClientStorage ACCOUNTS = 10 TRANSFERS = 10 ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def init(ids, sum): # transaction start for i in ids: accounts[i] = sum # transaction end init(ids, 1000) for i in range(0, TRANSFERS): a = choice(ids) b = choice(filter(lambda x: x!= a, ids)) sum = randint(1, 5) * 100 pool.apply_async(func=transfer, args=(a,b,sum)) pool.close() pool.join() print total(ids) def total(ids): # transaction start total = 0 for i in ids: total += accounts[i] # transaction end return total def transfer(a, b, sum): # transaction start accounts[a] -= sum accounts[b] += sum # transaction end

Bank from random import choice, randint from multiprocessing import Pool from durus.connection import Connection from durus.client_storage import ClientStorage ACCOUNTS = 10 TRANSFERS = 10 ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def init(ids, sum): transaction = Connection(ClientStorage()) accounts = transaction.get_root() for i in ids: accounts[i] = sum transaction.commit() def total(ids): transaction = Connection(ClientStorage()) accounts = transaction.get_root() total = 0 for i in ids: total += accounts[i] transaction.commit() def transfer(a, b, sum): transaction = Connection(ClientStorage()) accounts = transaction.get_root() accounts[a] -= sum accounts[b] += sum transaction.commit() init(ids, 1000) for i in range(0, TRANSFERS): a = choice(ids) b = choice(filter(lambda x: x!= a, ids)) sum = randint(1, 5) * 100 pool.apply_async(func=transfer, args=(a,b,sum)) pool.close() pool.join() print total(ids) return total

Bank from random import choice, randint from multiprocessing import Pool from durus.connection import Connection from durus.client_storage import ClientStorage, ConflictError ACCOUNTS = 10 TRANSFERS = 10 ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def init(ids, sum): transaction = Connection(ClientStorage()) accounts = transaction.get_root() for i in ids: accounts[i] = sum transaction.commit() def total(ids): transaction = Connection(ClientStorage()) accounts = transaction.get_root() total = 0 for i in ids: total += accounts[i] transaction.commit() return total def transfer(a, b, sum): transaction = Connection(ClientStorage()) accounts = transaction.get_root() try: accounts[a] -= sum accounts[b] += sum transaction.commit() except ConflictError: transaction.abort() init(ids, 1000) for i in range(0, TRANSFERS): a = choice(ids) b = choice(filter(lambda x: x!= a, ids)) sum = randint(1, 5) * 100 pool.apply_async(func=transfer, args=(a,b,sum)) pool.close() pool.join() print total(ids)

Bank from random import choice, randint from multiprocessing import Pool from durus.connection import Connection from durus.client_storage import ClientStorage, ConflictError ACCOUNTS = 10 TRANSFERS = 10 ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def init(ids, sum): transaction = Connection(ClientStorage()) accounts = transaction.get_root() for i in ids: accounts[i] = sum transaction.commit() def total(ids): transaction = Connection(ClientStorage()) accounts = transaction.get_root() total = 0 for i in ids: total += accounts[i] transaction.commit() return total def transfer(a, b, sum): transaction = Connection(ClientStorage()) accounts = transaction.get_root() while True: try: accounts[a] -= sum accounts[b] += sum transaction.commit() return except ConflictError: transaction.abort() init(ids, 1000) for i in range(0, TRANSFERS): a = choice(ids) b = choice(filter(lambda x: x!= a, ids)) sum = randint(1, 5) * 100 pool.apply_async(func=transfer, args=(a,b,sum)) pool.close() pool.join() print total(ids)

Bank class Transaction (Process): def init (self, f, args, kwargs={}): Process. init (self) self._f, self._a, self._kw = f, args, kwargs self.ppipe, self.pipe = Pipe() self._returned, self._result = False, None def run(self): transaction = Connection(ClientStorage()) while True: try: memory = transaction.get_root() result = self._f(memory, *self._a, **self._kw) transaction.commit() self.pipe.send(result) self.pipe.close() break except ConflictError: transaction.abort() def result(self): if not self._returned: self._result = self.ppipe.recv() self._returned = True return self._result

Bank class Transaction (Process): def init (self, f, args, kwargs={}): Process. init (self) self._f, self._a, self._kw = f, args, kwargs self.ppipe, self.pipe = Pipe() self._returned, self._result = False, None def run(self): transaction = Connection(ClientStorage()) while True: try: memory = transaction.get_root() result = self._f(memory, *self._a, **self._kw) transaction.commit() self.pipe.send(result) self.pipe.close() break except ConflictError: transaction.abort() def result(self): if not self._returned: self._result = self.ppipe.recv() self._returned = True return self._result # pool = Pool(processes=4) # pool = Pool(processes=4, initializer=transaction) t = Transaction(init, (ids, 1000)) t.start() t.join() ts = [] for i in range(0, TRANSFERS): #... t = Transaction(transfer, (a,b,sum)) # pool.apply_async(func=t.start) t.start() ts.append(t) for t in ts: t.join() t = Transaction(total, (ids,)) t.start() t.join() print t.result()

Bank class Transaction (Process): def init (self, f, args, kwargs={}): Process. init (self) self._f, self._a, self._kw = f, args, kwargs self.ppipe, self.pipe = Pipe() self._returned, self._result = False, None def run(self): transaction = Connection(ClientStorage()) while True: try: memory = transaction.get_root() result = self._f(memory, *self._a, **self._kw) transaction.commit() self.pipe.send(result) self.pipe.close() break except ConflictError: transaction.abort() def result(self): if not self._returned: self._result = self.ppipe.recv() self._returned = True return self._result # pool = Pool(processes=4) # pool = Pool(processes=4, initializer=transaction) t = Transaction(init, (ids, 1000)) t.start() t.join() ts = [] for i in range(0, TRANSFERS): #... t = Transaction(transfer, (a,b,sum)) # pool.apply_async(func=t.start) t.start() ts.append(t) for t in ts: t.join() t = Transaction(total, (ids,)) t.start() t.join() print t.result()

Bank def transaction(f, a, kw={}): transaction = Connection(ClientStorage()) while True: try: memory = transaction.get_root() result = f(memory, *a, **kw) transaction.commit() return result except ConflictError: transaction.abort()

Bank from random import choice, randint from multiprocessing import Pool from durus.connection import Connection from durus.client_storage import ClientStorage, ConflictError ACCOUNTS = 10 TRANSFERS = 10 def total(ids): def _total(accounts, ids): total = 0 for i in ids: total += accounts[i] return total return transaction(_total, (ids,)) ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def transaction(f, a, kw={}): transaction = Connection(ClientStorage()) while True: try: memory = transaction.get_root() result = f(memory, *a, **kw) transaction.commit() return result except ConflictError: transaction.abort() def init(ids, sum): def _init(accounts, ids, sum): for i in ids: accounts[i] = sum return transaction(_init, (ids, sum,)) def transfer(a, b, sum): def _transfer(accounts, a, b, sum): accounts[a] -= sum accounts[b] += sum return transaction(_transfer, (a, b, sum)) init(ids, 1000) for i in range(0, TRANSFERS): a = choice(ids) b = choice(filter(lambda x: x!= a, ids)) sum = randint(1, 5) * 100 pool.apply_async(func=transfer, args=(a,b,sum)) pool.close() pool.join() print total(ids)

Pamięć transakcyjna Optymistyczna

Pamięć transakcyjna Optymistyczna czynności są powtarzane jeśli są konflikty czuła na liczbę transakcji i zasobow extra kod

Pamięć transakcyjna Optymistyczna czynności są powtarzane jeśli są konflikty czuła na liczbę transakcji i zasobow extra kod Uniwersalność

Pamięć transakcyjna Optymistyczna czynności są powtarzane jeśli są konflikty czuła na liczbę transakcji i zasobow extra kod Uniwersalność ten sam schemat rozwiązuje większość problemów

Pamięć transakcyjna Optymistyczna czynności są powtarzane jeśli są konflikty czuła na liczbę transakcji i zasobow extra kod Uniwersalność ten sam schemat rozwiązuje większość problemów Poprawa efektywności

Pamięć transakcyjna Optymistyczna czynności są powtarzane jeśli są konflikty czuła na liczbę transakcji i zasobow extra kod Uniwersalność ten sam schemat rozwiązuje większość problemów Poprawa efektywności (jeśli nie ma dużo konfliktów)

Pamięć transakcyjna Optymistyczna czynności są powtarzane jeśli są konflikty czuła na liczbę transakcji i zasobow extra kod Uniwersalność ten sam schemat rozwiązuje większość problemów Poprawa efektywności (jeśli nie ma dużo konfliktów) Akcje muszą dać się powtarzać (i nie mogą mieć nieodwracalnych efektów)

Bank // Deuce STM // compile with -javaagent:bin/deuceagent.jar public class Bank { public static final int TRANSFERS = 10; public static final int ACCOUNTS = 100; } private final double[] accounts = new double[accounts]; public Bank() { for (int i = 0; i < accounts.length; i++) { accounts[i] = 200; } } @Atomic public void total() { double total = 0d; for (int i = 0; i < accounts.length; i++) { total += accounts[i]; } } @Atomic public void transfer(int a, int b, double sum) { accounts[a] -= sum; accounts[b] += sum; } public static void main(string[] args) { final Random random = new Random(); final Bank bank = new Bank(); List<Thread> transactions = new LinkedList<Thread>(); } for (int i = 0; i < Bank.TRANSFERS; i++) { final int a = random.nextint(bank.accounts); final int b = random.nextint(bank.accounts); final double sum = 5d + random.nextdouble() % 15d; Thread t = new Thread() { public void run() { bank.transfer(a, b, sum); } }; t.start(); transactions.add(t); } Thread t = new Thread() { public void run() { bank.total(); } }; t.start(); transactions.add(t); for (Thread thread : transactions) { thread.join(); }

Bank from random import choice, randint from multiprocessing import Pool from durus.connection import Connection from durus.client_storage import ClientStorage, ConflictError ACCOUNTS = 10 TRANSFERS = 10 def total(ids): def _total(accounts, ids): total = 0 for i in ids: total += accounts[i] return total return transaction(_total, (ids,)) ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def transaction(f, a, kw={}): transaction = Connection(ClientStorage()) while True: try: memory = transaction.get_root() result = f(memory, *a, **kw) transaction.commit() return result except ConflictError: transaction.abort() def init(ids, sum): def _init(accounts, ids, sum): for i in ids: accounts[i] = sum return transaction(_init, (ids, sum,)) def transfer(a, b, sum): def _transfer(accounts, a, b, sum): accounts[a] -= sum accounts[b] += sum return transaction(_transfer, (a, b, sum)) init(ids, 1000) for i in range(0, TRANSFERS): a = choice(ids) b = choice(filter(lambda x: x!= a, ids)) sum = randint(1, 5) * 100 pool.apply_async(func=transfer, args=(a,b,sum)) pool.close() pool.join() print total(ids)

Bank from random import choice, randint from multiprocessing import Pool from durus.connection import Connection from durus.client_storage import ClientStorage, ConflictError ACCOUNTS = 10 TRANSFERS = 10 def total(ids): def _total(accounts, ids): total = 0 for i in ids: total += accounts[i] return total return transaction(_total, (ids,)) ids = ["id_" + str(i) for i in range(0, ACCOUNTS)] accounts = {} def transaction(f, a, kw={}): transaction = Connection(ClientStorage()) while True: try: memory = transaction.get_root() result = f(memory, *a, **kw) transaction.commit() return result except ConflictError: transaction.abort() def init(ids, sum): def _init(accounts, ids, sum): for i in ids: accounts[i] = sum return transaction(_init, (ids, sum,)) def transfer(a, b, sum): def _transfer(accounts, a, b, sum): ask_user_for_authentication(a, b, sum) if _: accounts[a] -= sum accounts[b] += sum return transaction(_transfer, (a, b, sum)) init(ids, 1000) for i in range(0, TRANSFERS): a = choice(ids) b = choice(filter(lambda x: x!= a, ids)) sum = randint(1, 5) * 100 pool.apply_async(func=transfer, args=(a,b,sum)) pool.close() pool.join() print total(ids)

Globalny zamek!

Globalny zamek!

Posortowane zamki Pesymistyczne transakcje

Ale zamki są trudne?

Tak Ale zamki są trudne?

Ale zamki są trudne? Tak... ale dlaczego?

Ale zamki są trudne? Tak... ale dlaczego? Deadlock

Ale zamki są trudne? Tak... ale dlaczego? Deadlock Pamiętanie który zamek jest do czego i kompozycyjność

Ale zamki są trudne? Tak... ale dlaczego? Deadlock Pamiętanie który zamek jest do czego i kompozycyjność Dodatkowy kod

Ale zamki są trudne? Tak... ale dlaczego? Deadlock Pamiętanie który zamek jest do czego i kompozycyjność Dodatkowy kod zamknąć zamki w transakcje

Ale zamki są trudne? Tak... ale dlaczego? Deadlock Pamiętanie który zamek jest do czego i kompozycyjność po jednym zamku na obiekt współdzielony Dodatkowy kod zamknąć zamki w transakcje

Ale zamki są trudne? Tak... ale dlaczego? Deadlock sortowanie zamków, 2PL Pamiętanie który zamek jest do czego i kompozycyjność po jednym zamku na obiekt współdzielony Dodatkowy kod zamknąć zamki w transakcje

Posortowane zamki

Posortowane zamki

Posortowane zamki

Posortowane zamki

Posortowane zamki

Posortowane zamki

Posortowane zamki from multiprocessing import Lock accounts, locks = {}, {} for i in range(0, ACCOUNTS): accounts[i] = 200 locks[i] = Lock() def transfer(a, b, sum): _locks = [locks[a], locks[b]] _locks.sort(key = lambda x: str(x)) for lock in _locks: lock.acquire() accounts[a] -= sum locks[a].release() accounts[b] += sum locks[b].release()

Kiedy czego używać? Wątki funcyjne

Kiedy czego używać? Wątki funcyjne niezależne zadania

Kiedy czego używać? Wątki funcyjne niezależne zadania Transakcje

Kiedy czego używać? Wątki funcyjne niezależne zadania Transakcje wszystko co można powtarzać, bez bardzo dużej konkurencji o zasoby

Kiedy czego używać? Wątki funcyjne niezależne zadania Transakcje wszystko co można powtarzać, bez bardzo dużej konkurencji o zasoby Posortowane zamki

Kiedy czego używać? Wątki funcyjne niezależne zadania Transakcje wszystko co można powtarzać, bez bardzo dużej konkurencji o zasoby Posortowane zamki wszystko czego nie można powtarzać

Kiedy czego używać? Wątki funcyjne niezależne zadania Transakcje wszystko co można powtarzać, bez bardzo dużej konkurencji o zasoby Posortowane zamki wszystko czego nie można powtarzać Globalny zamek

Kiedy czego używać? Wątki funcyjne niezależne zadania Transakcje wszystko co można powtarzać, bez bardzo dużej konkurencji o zasoby Posortowane zamki wszystko czego nie można powtarzać Globalny zamek najlepiej nigdy

Kiedy czego używać? Wątki funcyjne niezależne zadania Transakcje wszystko co można powtarzać, bez bardzo dużej konkurencji o zasoby Posortowane zamki wszystko czego nie można powtarzać Globalny zamek najlepiej nigdy

Koło Naukowe SKiSR Koło Naukowe SKiSR http://dsg.cs.put.poznan.pl/student-club/

Koło Naukowe SKiSR Koło Naukowe SKiSR http://dsg.cs.put.poznan.pl/student-club/ konrad.siek@cs.put.edu.pl