Евгений Кирпичёв Многопоточное программирование (Full)1. Ìíîãîïîòî÷íîå ïðîãðàììèðîâàíèå è Java
Êîððåêòíîñòü, ïàòòåðíû, ïîäõîäû
Åâãåíèé Êèðïè÷¼â
18 àïðåëÿ 2010 ã.
Îáñóæäåíèå:
http://community.livejournal.com/ru_java/929773.html
2. Öåëü äîêëàäà
Ðàñøèðèòü êðóãîçîð â îáëàñòè ìíîãîïîòî÷íîãî
ïðîãðàììèðîâàíèÿ âîîáùå è íà Java â ÷àñòíîñòè.
Êîððåêòíîñòü
Êàê ñôîðìóëèðîâàòüD ïîâûñèòüD ãàðàíòèðîâàòü
Èíñòðóìåíòû
Ïàòòåðíû è âåëîñèïåäû
Ïîäõîäû è ôèøêè ðàçíûõ ÿçûêîâ
5. Êëàññèôèêàöèÿ ìíîãîïîòî÷íûõ ïðîãðàìì (contd.)
Ïðîãðàììû áûâàþò ðàçíûå.
Raytracer Server IDE
Ñêîëüêî çàäà÷? Ìíîãî Ìíîãî Ìàëî
Çàâèñèìû? Íåò Íåò Äà
Îáùèå ðåñóðñû? Íåò Äà Äà
Òðóäíîñòü CPU perf IO perf Êîððåêòíîñòü
8. Ïðè÷èíû áàãîâ
Êîðåíü âñåõ çîë èçìåíÿåìîå âî âðåìåíè ñîñòîÿíèå.
N íèòåé, K ñîñòîÿíèé ⇒ O(KN) ïåðåïëåòåíèé
Ïðîìåæóòî÷íûå ñîñòîÿíèÿ âèäèìû
Äàæå âûçîâ ìåòîäà ýòî áîëüøå íå ÷åðíûé ÿùèê
Åãî òåëî áîëüøå íå àòîìàðíî
Êîððåêòíûå ìíîãîïîòî÷íûå ïðîãðàììû íå ìîäóëüíû
ƒequenti—ly ™orre™t + ƒequenti—lly ™orre™t = gon™urrently
™orre™t
10. Äîêàçóåìàÿ êîððåêòíîñòü
Face it:
Ëèáî ïðîãðàììà äîêàçóåìî êîððåêòíà
Ëèáî îíà, ïî÷òè íàâåðíÿêà, íåêîððåêòíà
Ïóñòü âåðîÿòíîñòü áàãà 10−8
109 âûçîâîâ çà íåäåëþ è âåðîÿòíîñòü 1 − e−10 ≈ 1
Ïðè íåïðåðûâíîì òåñòèðîâàíèè îøèáêà òîæå âñïëûâåò
òîëüêî ÷åðåç íåäåëþ
Ðàáîòàåò íà áóìàãå èëè íå ðàáîòàåò âîîáùå
11. Äîêàçóåìàÿ êîððåêòíîñòü
Face it:
Ëèáî ïðîãðàììà äîêàçóåìî êîððåêòíà
Ëèáî îíà, ïî÷òè íàâåðíÿêà, íåêîððåêòíà
Tony Hoare:
There are two ways of constructing a software design.
One way is to make it so simple that there are obviously no
deciencies, and the other way is to make it so complicated that
there are no obvious deciencies.
The rst method is far more dicult.
13. Ôîðìàëüíûå ìåòîäû
À çà÷åì òîãäà îíè âîîáùå íóæíû?
×òîáû îïèñûâàòü ñèñòåìó ïîëóôîðìàëüíî
×òîáû ÷óÿòü: ôîðìàëèçóåìà ëè ñèñòåìà â ïðèíöèïå?
Åñëè íåò @ñèñòåìà ñëèøêîì çàïóòàíàA î êîððåêòíîñòè
ìîæíî çàáûòüF
14. Ôîðìàëüíûå ìåòîäû
Ìîé îïûò: äîñòàòî÷íî ïîïûòàòüñÿ ôîðìàëèçîâàòü ñèñòåìó:
Âñïëûâàþò ïðîòèâîðå÷èÿ, íåäîãîâîðêè â òðåáîâàíèÿõ
Âûäåëÿþòñÿ êîìïîíåíòû áåç ÷åòêîé ñïåöèôèêàöèè
ÁëàæåíD êòî âåðóåòD ÷òî îíè
”
è òàê“ ðàáîòàþò
17. Ñòðóêòóðà Êðèïêå
Ñòðóêòóðà Êðèïêå ≈ ãðàô ñîñòîÿíèé.
Ìíîæåñòâî ñîñòîÿíèé
Íåêîòîðûå íà÷àëüíûå
Íåêîòîðûå ñîåäèíåíû ïåðåõîäîì
Ïåðåõîä áåçóñëîâíûé
Ìíîæåñòâî ôàêòîâ
 êàæäîì ñîñòîÿíèè âåðíû íåêîòîðûå ôàêòû.
19. Ñòðóêòóðà Êðèïêå
Ïåðåõîäû íå ïîäïèñàíû, ïîòîìó ÷òî:
Íîìåð ñîñòîÿíèÿ ïîëíîñòüþ îïèñûâàåò ñîñòîÿíèå
ïðîãðàììû
Åñëè ïåðåõîä óñëîâíûé íàäî ïîäåëèòü ñîñòîÿíèå íà äâà
ÒîD â êîòîðîì óñëîâèå âåðíî @ïåðåõîä ìîæåò ïðîèçîéòèA
ÒîD â êîòîðîì óñëîâèå íåâåðíî @ïåðåõîä íå ìîæåò
ïðîèçîéòèA
Ïðîãðàììó ìîæíî ñòðàíñëèðîâàòü â ñòðóêòóðó Êðèïêå
Ñòðóêòóðû Êðèïêå ïðåêðàñíî ïîääàþòñÿ âåðèôèêàöèè
20. LTL
Ëèíåéíàÿ òåìïîðàëüíàÿ ëîãèêà (Linear Temporal Logic).
Ðàññóæäàåò î ïîñëåäîâàòåëüíîñòÿõ ñîñòîÿíèé ìèðà âî âðåìåíè.
Åñòü çàïðîñ ⇒ êîãäà-íèáóäü áóäåò îòâåò
Áëîêèðîâêà çàïðîøåíà ⇒ êëèåíò áóäåò îáñëóæåí ñêîëü
óãîäíî áîëüøîå ÷èñëî ðàç, ïîêà íå îòïóñòèò åå
. . .
Ïðåëåñòè:
Êðàòêàÿ, ïîíÿòíàÿ, ìîùíàÿ è îäíîçíà÷íàÿ
LTL-ñâîéñòâà ëåãêî âåðèôèöèðóþòñÿ äàæå âðó÷íóþ
Îòíîñèòåëüíî ñòðóêòóð Êðèïêå
Ìíîãî ìîùíûõ èíñòðóìåíòîâ
21. Ôîðìóëû LTL
p1, p2, . . . Ïåðåìåííûå
A ∧ B, ¬A. . . Ëîãè÷åñêèå ñâÿçêè
XA Â ñëåäóþùèé ìîìåíò A (neXt)
GA ≡ A Âñåãäà A (Globally)
FA ≡ ♦A Êîãäà-íèáóäü A (Future)
AUB A, ïî êðàéíåé ìåðå äî íàñòóïëåíèÿ B
25. Ñâîéñòâà
Ñïðàâåäëèâîñòü (fairness)
Òî, ÷òî ìîæåò ïðîèçîéòè ïðîèçîéäåò
Ñëàáàÿ: ♦ Req → ♦Ack
Ðåñóðñ çàïðîøåí @è îñòàåòñÿ çàïðîøåííûìA →
êîãäàEíèáóäü áóäåò âûäàí
Ñèëüíàÿ: ♦Req → ♦Ack
Íèòü áåñêîíå÷íî ìíîãî ðàç èñïîëíèìà @èìååò íå ñàìûé
íèçêèé ïðèîðèòåò èç íåáëîêèðîâàííûõA → êîãäàEíèáóäü
ïîëó÷èò êâàíò
Àíòîíèì starvation (ãîëîäàíèå)
26. Ïðèìåðû LTL-ñâîéñòâ
Óñòðîéñòâî íå âûêëþ÷àåòñÿ ñàìî ïî ñåáå
(isOn → (isOn U (turnOPressed ∨ noBattery))
Íå ðåæå ÷åì ðàç â 5 òàêòîâ âêëþ÷àåòñÿ êîíòðîëëåð
äâèãàòåëÿ
F5(activeThread == ENGINE_CONTROLLER)
27. Model checking
Íàóêà î ïðîâåðêå ñâîéñòâ ïðîãðàìì (íàïðèìåð, LTL) íà îñíîâå
èõ ìîäåëåé (íàïðèìåð, ñòðóêòóð Êðèïêå) Model checking.
Ïðåìèÿ Òüþðèíãà 2007 çà äîñòèæåíèÿ â îáëàñòè model
checking, ñäåëàâøèå åãî ïðèìåíèìûì äëÿ ïðîåêòîâ ðåàëüíîãî
ðàçìåðà.
28. Èíñòðóìåíò: SPIN
Ïîâñåìåñòíî èñïîëüçóåìûé ÿçûê + âåðèôèêàòîð LTL-ñâîéñòâ
äëÿ ìíîãîçàäà÷íûõ ñèñòåì.
Ëàóðåàò ACM Software System award (2001) (äðóãèå ëàóðåàòû:
Unix, TeX, Java, Apache, TCP/IP, . . . ).
Ñè-ïîäîáíûé ñèíòàêñèñ
Äëÿ íàðóøåííûõ ñâîéñòâ ãåíåðèðóåòñÿ íàðóøàþùàÿ èõ
òðàññà
(óðîäëèâûé, íî òåðïèìûé) GUI
ß ïðîâåðÿë: Ïðèãîäíî äëÿ ïðèìåíåíèÿ íà ïðàêòèêå.
http://spinroot.com/spin/whatispin.html îôèöèàëüíûé ñàéòF
31. Áëèæå ê äåëó
Êàê ðàññóæäàòü î ðåàëüíûõ ïðîãðàììàõ?
Àêñèîìàòèêà: Java memory model è ò.ï.
Îñíîâíûå ïàðàìåòðû (äîêóìåíòèðóéòå èõ!):
„hre—d s—fety
Âîçìîæíîñòü áëîêèðîâàíèÿY èñïîëüçóåìûå áëîêèðîâêè è
ïîðÿäîê èõ âçÿòèÿ
Âåðõíÿÿ ãðàíèöà âðåìåíè âûïîëíåíèÿ @êîíñòàíòà èëè íåòA
Ðåàêöèÿ íà ïðåðûâàíèå
Ðåàêöèÿ íà îøèáêè
Ðåàêöèÿ íà òàéìàóòû
F F F
32. Java Memory Model
Ñ íåé íåîáõîäèìî îçíàêîìèòüñÿ. Ìíîãî ñþðïðèçîâ.
Íåëüçÿ ñîçäàâàòü íèòè â êîíñòðóêòîðå
Íå-nal ïîëÿ íå ïîòîêîáåçîïàñíû (äàæå åñëè íå ìåíÿþòñÿ)
. . .
Ñì. appendix, êíèãó JCIP, JLS.
33. Thread safety
Immutable. Ó îáúåêòà âñåãî 1 ñîñòîÿíèå.
Thread-safe. Êàæäàÿ îïåðàöèÿ ñàìà ïî ñåáå
áåçîïàñíà/àòîìàðíà. Ïîñëåäîâàòåëüíîñòè íåò.
Ïîñëåäîâàòåëüíîñòè íóæíî êîîðäèíèðîâàòü èçâíå
ÄîêóìåíòèðóéòåD êàêèå èìåííî âñåEòàêè áåçîïàñíû
ÏðèìåðX Áàíêîâñêèé ñ÷åò
34. Thread safety
Thread-compatible. Ìîæíî èñïîëüçîâàòü ìíîãîïîòî÷íî,
åñëè íå âûçûâàòü îïåðàöèè îäíîâðåìåííî.
Íóæíà âíåøíÿÿ ñèíõðîíèçàöèÿD íî ñ íåé áóäåò ðàáîòàòü
Thread-hostile. Âîîáùå íåëüçÿ èñïîëüçîâàòü ìíîãîïîòî÷íî.
Thread-conned. Ìîæíî èñïîëüçîâàòü èç êîíêðåòíîé íèòè.
ÏðèìåðX ƒwing
35. CheckThread
Íàáîð àííîòàöèé äëÿ äîêóìåíòèðîâàíèÿ thread safety.
Åñòü ïëàãèí ê IDEA.
Î÷åíü ïîëåçíî.
Ïðèìåð
@ThreadSafe class SynchronizedInteger {
@GuardedBy(this) private int value;
synchronized int get() { return value; }
synchronized void set(int v) { value = v; }
}
36. Java Path Finder
Âèðòóàëüíàÿ ìàøèíà, óìåþùàÿ ñèìâîëüíî âûïîëíÿòü Java-êîä
è âåðèôèöèðîâàòü ñâîéñòâà äëÿ âñåõ âîçìîæíûõ çàïóñêîâ ñ
ó÷åòîì ìíîãîïîòî÷íîñòè. Ñäåëàíî â NASA.
http://javapathfinder.sourceforge.net/
http://sourceforge.net/projects/visualjpf/ q…s
http://www.visserhome.com/willem/presentations/
ase06jpftut.ppt ïîäîáèå òóòîðèàëà
ÓòâåðæäàåòñÿD ÷òî ñïðàâëÿåòñÿ ñ ïðîåêòàìè äî IHuvygF
Íàõîäèë áàãè â xeƒeEîâñêîì ñîôòå @â ìàðñîõîäåD íàïðèìåðA
Îñíîâàí íà ƒ€sx
Åñòü —ntEt—sk è ïëàãèí ê e™lipseY ðàñøèðÿåì
ß íàïèñàë ìàëåíüêèé ïðèìåð ñ äåäëîêîìF ÑðàáîòàëîF
37. Äðóãèå òóëû
Ñòàòè÷åñêèé àíàëèç ìíîãîïîòî÷íûõ îøèáîê åñòü è â:
PMD
FindBugs (åñòü ïëàãèí ê IDEA)
Ïðîâåðåíî: ïîìîãàåò (è íå òîëüêî îò ìíîãîïîòî÷íûõ).
38. Ôèëîñîôñêîå èçáàâëåíèå îò áàãîâ
Íàäî óìåíüøèòü O(KN).
Óìåíüøèòü ÷èñëî íàáëþäàåìûõ ñîñòîÿíèé (K)
smmut—˜ility
Èíêàïñóëÿöèÿ ñîñòîÿíèÿ
Âûñîêîóðîâíåâûå îïåðàöèè
Ôàêòîðèçàöèÿ
Ñèíõðîíèçàöèÿ
Íàâÿçàòü òðàññàì ýêâèâàëåíòíîñòü
Èäåìïîòåíòíûå îïåðàöèè
foo();foo(); ∼ foo();
Êîììóòàòèâíûå @íåçàâèñèìûåA îïåðàöèè
foo();bar(); ∼ bar();foo();
 ò.÷. èíêàïñóëÿöèÿ è íåçàâèñèìûå îáúåêòû
Ñ÷èòàòü áîëüøåå ÷èñëî òðàññ êîððåêòíûìè (îñëàáèòü
òðåáîâàíèÿ)
39. Immutability
Íåëüçÿ èçìåíèòü âîîáùå ⇒ íåëüçÿ èçìåíèòü íåïðàâèëüíî, íå â
òîì ïîðÿäêå . . .
Âñå ïîëÿ private, nal, è èõ êëàññû ñàìè ïî ñåáå immutable
Èíà÷å ïîëå ìîæåò èçìåíèòü êòîEòî äðóãîé
Èíà÷å íàðóøèòñÿ thre—d s—fety @t—v— wemory wodelA
Èíà÷å èçìåíåíèå ìîæåò ïðîèçîéòè òàéêîì
Ñàì êëàññ nal
Èíà÷å ìîæíî ñîçäàòü mut—˜le ïîòîìêà è ïåðåäàòü åãî
êîìóEíèáóäü â êà÷åñòâå îáúåêòà áàçîâîãî êëàññà
Áàçîâûé êëàññ òîæå immutable
Èíà÷å ìîæíî èçìåíèòü ñîñòîÿíèå ïðè ïîìîùè îïåðàöèé
áàçîâîãî êëàññà
40. Immutability
Íåëüçÿ èçìåíèòü âîîáùå ⇒ íåëüçÿ èçìåíèòü íåïðàâèëüíî, íå â
òîì ïîðÿäêå . . .
Âñå ïîëÿ private, nal, è èõ êëàññû ñàìè ïî ñåáå immutable
Èíà÷å ïîëå ìîæåò èçìåíèòü êòîEòî äðóãîé
Èíà÷å íàðóøèòñÿ thre—d s—fety @t—v— wemory wodelA
Èíà÷å èçìåíåíèå ìîæåò ïðîèçîéòè òàéêîì
Ñàì êëàññ nal
Èíà÷å ìîæíî ñîçäàòü mut—˜le ïîòîìêà è ïåðåäàòü åãî
êîìóEíèáóäü â êà÷åñòâå îáúåêòà áàçîâîãî êëàññà
Áàçîâûé êëàññ òîæå immutable
Èíà÷å ìîæíî èçìåíèòü ñîñòîÿíèå ïðè ïîìîùè îïåðàöèé
áàçîâîãî êëàññà
41. Immutability
Íåëüçÿ èçìåíèòü âîîáùå ⇒ íåëüçÿ èçìåíèòü íåïðàâèëüíî, íå â
òîì ïîðÿäêå . . .
Âñå ïîëÿ private, nal, è èõ êëàññû ñàìè ïî ñåáå immutable
Èíà÷å ïîëå ìîæåò èçìåíèòü êòîEòî äðóãîé
Èíà÷å íàðóøèòñÿ thre—d s—fety @t—v— wemory wodelA
Èíà÷å èçìåíåíèå ìîæåò ïðîèçîéòè òàéêîì
Ñàì êëàññ nal
Èíà÷å ìîæíî ñîçäàòü mut—˜le ïîòîìêà è ïåðåäàòü åãî
êîìóEíèáóäü â êà÷åñòâå îáúåêòà áàçîâîãî êëàññà
Áàçîâûé êëàññ òîæå immutable
Èíà÷å ìîæíî èçìåíèòü ñîñòîÿíèå ïðè ïîìîùè îïåðàöèé
áàçîâîãî êëàññà
42. Immutability
Íåëüçÿ èçìåíèòü âîîáùå ⇒ íåëüçÿ èçìåíèòü íåïðàâèëüíî, íå â
òîì ïîðÿäêå . . .
Âñå ïîëÿ private, nal, è èõ êëàññû ñàìè ïî ñåáå immutable
Èíà÷å ïîëå ìîæåò èçìåíèòü êòîEòî äðóãîé
Èíà÷å íàðóøèòñÿ thre—d s—fety @t—v— wemory wodelA
Èíà÷å èçìåíåíèå ìîæåò ïðîèçîéòè òàéêîì
Ñàì êëàññ nal
Èíà÷å ìîæíî ñîçäàòü mut—˜le ïîòîìêà è ïåðåäàòü åãî
êîìóEíèáóäü â êà÷åñòâå îáúåêòà áàçîâîãî êëàññà
Áàçîâûé êëàññ òîæå immutable
Èíà÷å ìîæíî èçìåíèòü ñîñòîÿíèå ïðè ïîìîùè îïåðàöèé
áàçîâîãî êëàññà
43. Immutability
Íåëüçÿ èçìåíèòü âîîáùå ⇒ íåëüçÿ èçìåíèòü íåïðàâèëüíî, íå â
òîì ïîðÿäêå . . .
Âñå ïîëÿ private, nal, è èõ êëàññû ñàìè ïî ñåáå immutable
Èíà÷å ïîëå ìîæåò èçìåíèòü êòîEòî äðóãîé
Èíà÷å íàðóøèòñÿ thre—d s—fety @t—v— wemory wodelA
Èíà÷å èçìåíåíèå ìîæåò ïðîèçîéòè òàéêîì
Ñàì êëàññ nal
Èíà÷å ìîæíî ñîçäàòü mut—˜le ïîòîìêà è ïåðåäàòü åãî
êîìóEíèáóäü â êà÷åñòâå îáúåêòà áàçîâîãî êëàññà
Áàçîâûé êëàññ òîæå immutable
Èíà÷å ìîæíî èçìåíèòü ñîñòîÿíèå ïðè ïîìîùè îïåðàöèé
áàçîâîãî êëàññà
44. Èíêàïñóëÿöèÿ ñîñòîÿíèÿ
Ïðîãðàììà êîððåêòíà ðîâíî íàñòîëüêî, íàñêîëüêî êîððåêòíû è
ñêîîðäèíèðîâàíû âñå, êòî ìîãóò ïîâëèÿòü íà ñîñòîÿíèå
îáúåêòà.
Ìîðàëü: ×åì ìåíüøå ñïîñîáîâ ïîâëèÿòü íà ñîñòîÿíèå, òåì
ëó÷øå.
Ìàëî êîìó äàâàòü ê íåìó äîñòóï
Ìàëî êîãî íàäî áóäåò êîîðäèíèðîâàòü
Äàâàòü äîñòóï â òåðìèíàõ ìàëîãî ÷èñëà âûñîêîóðîâíåâûõ
îïåðàöèé
Ìàëî êîìáèíàöèé îïåðàöèé íàäî ðàññìàòðèâàòü
Ìåíüøå íàðóøàåòñÿ öåëîñòíîñòü ìåæäó îïåðàöèÿìè
45. Âûñîêîóðîâíåâûå îïåðàöèè
Îïðåäåëåíèå: Âûñîêîóðîâíåâàÿ îïåðàöèÿ îïåðàöèÿ, íå
íàðóøàþùàÿ öåëîñòíîñòü ñèñòåìû.
AtomicInteger.getAndIncrement
ConcurrentMap.putIfAbsent
Bank.transfer
Äîñòàòî÷íî ïðàâèëüíî ðåàëèçîâàòü ñàìó îïåðàöèþ.
Ïðîåêòèðóéòå API â òàêîì ñòèëå, åñëè ýòî âîçìîæíî.
46. Âûñîêîóðîâíåâûå îïåðàöèè
×àñòíûé ñëó÷àé:
Ó îáúåêòà â ìåðó áîëüøîå ñîñòîÿíèå
Õî÷åòñÿ àòîìàðíî ïîìåíÿòü íåñêîëüêî åãî ÷àñòåé
Çàïèõíèòå ñîñòîÿíèå â îáúåêò è ïîìåíÿéòå àòîìàðíî
ññûëêó íà ýòîò îáúåêò
AtomicReference
×èñòî ôóíêöèîíàëüíûå ñòðóêòóðû äàííûõ âñåãäà
ïîòîêîáåçîïàñíû
http://tobega.blogspot.com/2008/03/
java-thread-safe-state-design-pattern.html
ÑìFòæF yk—s—kiD €urely fun™tion—l d—t— stru™turesF
47. Ôàêòîðèçàöèÿ
Ïðîãðàììà êîððåêòíà ðîâíî íàñòîëüêî, íàñêîëüêî êîððåêòíû è
ñêîîðäèíèðîâàíû âñå, êòî ìîãóò ïîâëèÿòü íà ñîñòîÿíèå
îáúåêòà.
Ìîðàëü: Íåçàâèñèìûå àñïåêòû ñîñòîÿíèÿ âûíîñèòü â
íåçàâèñèìûå îáúåêòû.
Ñëîæíîñòü ïàäàåò ñ (K1 + K2)N äî KN
1 + KN
2 (áðåä, íî ñóòü
ïðèìåðíî òàêàÿ).
50. Ôàêòîðèçàöèÿ
Ðàçîðâåì ëèøíþþ çàâèñèìîñòü ìåæäó íåçàâèñèìûìè
çàäà÷àìè.
class DataLoader {
PerClientLoader beginLoad(Client client);
}
class PerClientLoader {
void writeData(Data data);
void commit();
void rollback();
}
54. Ñèíõðîíèçàöèÿ (ñåðèàëèçàöèÿ äîñòóïà)
Åñëè íàäî çàùèòèòü äîñòóï ê êîìáèíàöèè îáúåêòîâ íàäî
ñèíõðîíèçèðîâàòüñÿ â îäèíàêîâîì ïîðÿäêå.
Èíà÷å äåäëîêè.
Òàê äåëàòü íå íàäî
void foo() {
synchronized(x) {
synchronized(y) {
...
}
}
}
void bar() {
synchronized(y) {
synchronized(x) {
...
}
}
}
55. Áîðüáà ñ äåäëîêàìè
Íóæåí ãëîáàëüíî ôèêñèðîâàííûé ïîðÿäîê áëîêèðîâîê.
Ýêçîòè÷åñêèé ñëó÷àé:
Òàê äåëàòü íå íàäî
void transfer(Account from,Account to,int money) {
synchronized(from) {
synchronized(to) {
..
}
}
}
56. Áîðüáà ñ äåäëîêàìè: Ýêçîòè÷åñêèé ñëó÷àé
Íóæåí ãëîáàëüíî ôèêñèðîâàííûé ïîðÿäîê áëîêèðîâîê.
Íàäî äåëàòü âîò òàê
void transfer(Account from,Account to,int money) {
synchronized(fromto ? from : to) {
synchronized(from?to ? to : from) {
..
}
}
}
Ïîäðîáíî ñì. Java Concurrency in Practice.
57. Åùå íåìíîãî î äåäëîêàõ
Íå ñòîèò âûçûâàòü ÷óæèå ìåòîäû (callbacks), äåðæà
áëîêèðîâêó (alien call). Òàêèå âûçîâû ëó÷øå ïðåâðàòèòü â
open call (âûçîâ âíå áëîêèðîâêè)
private void frobbleBar(Bar bar) {
ListBarListener copy;
synchronized (this) {
copy = new ArrayListBarListener(listeners);
}
for (Listener l : snapshot)
l.barFrobbled(bar);
}
Áîëåå îáùèé ñëó÷àé:
Ìèíèìèçèðóéòå ñëîæíîñòü è íåèçâåñòíîñòü êîäà âíóòðè
áëîêèðîâêè
Ñîâñåì õîðîøî, åñëè åãî äëèòåëüíîñòü îãðàíè÷åíà ñâåðõó
58. Åùå íåìíîãî î äåäëîêàõ
×àñòàÿ ïðè÷èíà äåäëîêîâ ðåñóðñû è ïóëû.
Äîñòóï ê ðåñóðñàì íàäî óïîðÿäî÷èâàòü, êàê è áëîêèðîâêè
Ïóëû + âçàèìîçàâèñèìûå çàäà÷è = ïðîáëåìà Thread
starvation deadlock
Ïóë çàáèò íèòÿìèD æäóùèìè ðåçóëüòàòà âû÷èñëåíèÿ
Âû÷èñëåíèå â î÷åðåäèD íî åãî íåêîìó íà÷àòü ïóë çàáèò
59. Ñèíõðîíèçàöèÿ è íàñëåäîâàíèå
Î÷åíü òðóäíî ñäåëàòü ýôôåêòèâíûé thread-safe êëàññ íà îñíîâå
non-thread-safe áàçîâîãî.
Ïðèäåòñÿ ïåðåãðóçèòü âñå äî åäèíîé îïåðàöèè
 ò.÷. è äëèòåëüíûå, òÿæåëîâåñíûå
Íå äàé áîã êàêèå-òî èç îïåðàöèé final
Êàê ñ íàñëåäîâàíèåì:
Design for inheritance or prohibit it
Design for thread-safety
60. Ñèíõðîíèçàöèÿ è íàñëåäîâàíèå
Ïàòòåðí Thread-safe interface:
Ïîäåëèòå ìåòîäû êîìïîíåíòà íà 2 ÷àñòè
(n—l èíòåðôåéñ C ðåàëèçàöèÿ
Ñèíõðîíèçàöèÿ òîëüêî â
”
èíòåðôåéñå“
”
Ðåàëèçàöèÿ“ âûçûâàåò òîëüêî
”
ðåàëèçàöèþ“
Íàñëåäíèêè íå áåñïîêîÿòñÿ î ñèíõðîíèçàöèè
Äîâîëüíî îáùèé ïàòòåðí
ñèíõðîíèçàöèÿ → òðàíçàêöèÿ ÁÄD òðàíçàêöèÿ undoD F F F
61. Èäåìïîòåíòíûå îïåðàöèè
foo();foo(); ∼ foo();
Òîãäà ìîæíî íå çàáîòèòüñÿ îá îãðàíè÷åíèè ÷èñëà âûçîâîâ
foo() (íî foo() äîëæíà áûòü thread-safe).
Îñîáåííî âàæíî â ðàñïðåäåëåííûõ è âåá-ñèñòåìàõ (ñ
íåíàäåæíûì ïîäòâåðæäåíèåì âûçîâà foo()).
×àñòûé ïðèìåð ëåíèâàÿ èíèöèàëèçàöèÿ.
64. Îñëàáëåíèå òðåáîâàíèé
Èíîãäà îáåñïå÷èòü æåñòêèå èíâàðèàíòû öåëîñòíîñòè
íåâîçìîæíî.
Îíè ìîãóò íàðóøàòüñÿ èçâíå
Åñòü âíåøíèå ïðîöåññûD íàðóøàþùèå öåëîñòíîñòü
Îíè íàì íå ïîäêîíòðîëüíû
ÍàïðèìåðX ñèíõðîíèçàöèÿ ôàéëîâD èçìåíÿåìûõ âíåøíèìè
ïðîöåññàìè
Èõ ñëèøêîì äîðîãî ïîääåðæèâàòü
ÍàïðèìåðD áîëüøàÿ ðàñïðåäåëåííàÿ ñèñòåìà
Ñèíõðîííîå ïðîòàëêèâàíèå èçìåíåíèÿ íà âñå ðåïëèêè
ñëèøêîì äîëãî
Ñ ó÷åòîì ïàäåíèé óçëîâ âñå åùå õóæå
Ëåíü ïèñàòü ñëîæíûé êîä :)
65. Îòðèöàòåëüíàÿ îáðàòíàÿ ñâÿçü
Ñóäÿ ïî âñåìó, îäèí èç ìîùíåéøèõ ïðèåìîâ ïðîåêòèðîâàíèÿ
íåêîòîðûõ êëàññîâ ìíîãîçàäà÷íûõ ñèñòåì.
Ñóòü:
”
Ñîñòîÿíèå ñèñòåìû âñåãäà öåëîñòíî“ î÷åíü òðóäíî è íå
âñåãäà íóæíî.
”
Ñîñòîÿíèå ñèñòåìû âñå öåëîñòíåå è öåëîñòíåå“ ëåãêî
îáåñïå÷èòü, ÷àñòî äîñòàòî÷íî.
Äåëàåì ñèñòåìó ëèøü ñòðåìÿùåéñÿ ê ñîñòîÿíèþ öåëîñòíîñòè.
66. Îòðèöàòåëüíàÿ îáðàòíàÿ ñâÿçü
Ïðèìåð ñòðóêòóðû:
Ñèñòåìà ïåðèîäè÷åñêè ïðîñûïàåòñÿ è îñìàòðèâàåòñÿ
Âû÷èñëÿåò, ÷åì ìèð îòëè÷àåòñÿ îò
”
èäåàëà“
ÊàêèåEòî äàííûå ñ ÷åìEòî íå ñîãëàñîâàíû
ÊàêèåEòî ãîòîâûå ê îáðàáîòêå äàííûå åùå íå
îáðàáàòûâàþòñÿ
ÊàêèåEòî äàííûå îáðàáàòûâàþòñÿ óæå ñëèøêîì äîëãîY
íàâåðíîåD îáðàáîò÷èê óìåð
F F F
Âûïîëíÿåò äåéñòâèÿ.
67. Îòðèöàòåëüíàÿ îáðàòíàÿ ñâÿçü
Ïëþñû ïîäõîäà
”
ñèñòåìà êàê ñõîäÿùèéñÿ ïðîöåññ“:
Îòðèöàòåëüíàÿ îáðàòíàÿ ñâÿçü
Ïîñëåäñòâèÿ áîëüøèíñòâà ïðîáëåì ðàíî èëè ïîçäíî
èñ÷åçíóòF
Âûñîêàÿ ìîäóëüíîñòü
Ñèñòåìà ðàñïàäàåòñÿ íà íàáîð ÷èñòî ëèíåéíûõ
àâòîìàòîâE
”
îáðàáîò÷èêîâ“F
Î÷åíü ïðîñòàÿ îòëàäêà è òåñòèðîâàíèå
Åñëè ÷òîEòî íå òàê ñèñòåìà ïðîñòî ïðèíÿëà
íåïðàâèëüíîå ðåøåíèå â îäíîì èç ñîñòîÿíèéF
ÌîæåòD ñàìî ðàññîñåòñÿD ìîæíî íå ôèêñèòü
68. Îòðèöàòåëüíàÿ îáðàòíàÿ ñâÿçü
Âûñîêàÿ óñòîé÷èâîñòü
Ñèñòåìà íåóÿçâèìà äëÿ
”
ñìåðòåëüíûõ“ áàãîâ @™orrupted
ñèíãëòîíûD óòå÷êè ðåñóðñîâAF
Ñäåëàòü ñîñòîÿíèå persistentD ïåðåçàïóñêàòü ïðîöåññF
Ãîòîâíîñòü ê ðàñïðåäåëåííîé ðàáîòå
Ñäåëàòü ñîñòîÿíèå ãëîáàëüíî âèäèìûì è îáåñïå÷èòü
ïðîñòåéøóþ áëîêèðîâêóF
70. Eventual consistency
Îòíîñèòñÿ ê ðàñïðîñòðàíåíèþ äàííûõ è èçìåíåíèé ïî
ðàñïðåäåëåííîé ñèñòåìå.
”
Êàæäîå èçìåíåíèå êîãäà-íèáóäü ñòàíåò âèäíî âñåé ñèñòåìå“.
Âèäèìî, åäèíñòâåííàÿ ýôôåêòèâíàÿ ìîäåëü â äåéñòâèòåëüíî
áîëüøèõ ñèñòåìàõ (Amazon, eBay è ò.ï.)
CAP Theorem
Choose any 2:
Consistency: âñå óçëû âèäÿò ñèñòåìó îäèíàêîâî
Availability: çàïðîñ ê æèâîìó óçëó îáÿçàòåëüíî ïîëó÷àåò îòâåò
Partition tolerance: ëþáîå ñîîáùåíèå ìåæäó óçëàìè ìîæåò
áûòü óòåðÿíî
71. Eventual consistency
Consistency, Availability, Partition Tolerance.
ACID
1 → BASE
2
ACID
Atomicity
Consistency
Isolation
Durability
BASE
Basically Available
Soft state
Eventually consistent
Soft state
The state . . . could be lost in a crash without permanent disruption
of the service features being used.
Clark, The design philosophy of the DARPA internet protocols
1
Êèñëîòà
2
􌑔֟
72. Further reading
http://www.webperformancematters.com/journal/2007/8/
21/asynchronous-architectures-4.html î
ìàñøòàáèðîâàíèè â em—zonF Î÷åíü ïîëåçíûå ñîâåòûF
http://www.infoq.com/interviews/
dan-pritchett-ebay-architecture î ìàñøòàáèðîâàíèè â
ef—y
http://roc.cs.berkeley.edu/ Èññëåäîâàòåëüñêèé ïðîåêò
‚e™overyEyriented gomputing
Áîðîòüñÿ ñ ïîñëåäñòâèÿìè îøèáîêD ïîñêîëüêó èñêîðåíèòü
âñå ïðè÷èíû íåâîçìîæíî
Íåñêîëüêî îñíîâíûõ ïðèíöèïîâ @èçîëÿöèÿD èçáûòî÷íîñòüD
undoD ñàìîäèàãíîñòèêàD ïåðåçàïóñêàåìîñòüA
Î÷åíü ðàçóìíîD åñëè ïîäóìàòüF
73. Àáñòðàãèðîâàíèå
Ìíîãîïîòî÷íóþ ïðîãðàììó íàìíîãî ëåã÷å íàïèñàòü è îòëàäèòü,
åñëè â íåé íåò íè÷åãî, êðîìå ñàìîé ñóòè.
Áàãè âûëåçàþò íà ïîâåðõíîñòü, íåò ñîáëàçíà ñêàçàòü Â íàøåé
çàäà÷å òàêàÿ ñèòóàöèÿ íåâîçìîæíà.
Àëãîðèòìû ëåã÷å îòëàæèâàòü ïî îòäåëüíîñòè.
Íå áëîêèðîâêà èíäåêñà íà ÷òåíèå èëè çàïèñü, à ïðîñòî
áëîêèðîâêà íà ÷òåíèå èëè çàïèñü
Íå î÷åðåäü e-mail'îâ, à îòêàçîóñòîé÷èâàÿ î÷åðåäü çàäà÷
Íå ïàðàëëåëüíûé ïîäñ÷åò ñëîâ, à MapReduce
Íå ïàðàëëåëüíàÿ ôèëüòðàöèÿ ìàññèâà, à ParallelArray
Ìîæåò îêàçàòüñÿ, ÷òî òàêàÿ øòóêà óæå åñòü.
75. Àáñòðàãèðîâàíèå: ïðèìåð
Ïðèâÿçêà ê âíåøíåé ñèñòåìå ñêà÷èâàíèÿ óðëîâ.
Çàäàíèÿ ïèøóòñÿ â ôàéëû
Âíåøíÿÿ ñèñòåìà èõ ïîäõâàòûâàåò
Îòâåòû òîæå ïèøóòñÿ â ôàéëû
Íàäî ïðåäîñòàâèòü àñèíõðîííûé API
void loadPage(url, onOk, onError)
77. Àáñòðàãèðîâàíèå: ïðèìåð
Devil in the details:
Íå çàôëóäèòü ñèñòåìó (áëîêèðîâàòüñÿ, åñëè ìíîãî çàäàíèé
”
â ïîëåòå“)
Ñëåäèòü çà òàéìàóòàìè (äîëãî íå îòâå÷àåò → onError)
Íå äîïóñêàòü ãîíîê ìåæäó îòâåòàìè è òàéìàóòàìè
Áåðå÷ü íèòêó ñëåæåíèÿ çà îòâåòàìè (âûçûâàòü
onOk,onError â îòäåëüíûõ íèòÿõ)
Îáðàáàòûâàòü ðåäèðåêòû
Îðãàíèçîâàòü ñèíõðîííûé shutdown
80. Àáñòðàãèðîâàíèå: ïðèìåð
Ñòàëî:
Ñåìàôîð äëÿ îãðàíè÷åíèÿ ÷èñëà çàäàíèé
”
â ïîëåòå“
Àáñòðàêòíûé ïàòòåðí
”
Stoppable“
Àáñòðàêòíûé
”
áàò÷åð“
Àáñòðàêòíûé
”
ïîëëåð“
Àáñòðàêòíûé
”
òàéìàóòåð“
Âñ¼ ýëåìåíòàðíî òåñòèðóåòñÿ (íàøëèñü áàãè)
Âñ¼ ïîëåçíî è ïîâòîðíî èñïîëüçóåìî
88. Ìîäåëè ìíîãîïîòî÷íûõ âû÷èñëåíèé
Ïàðàëëåëèçì:
MapReduce: Îãðîìíûå îáúåìû äàííûõ, ðàñïðåäåëåííàÿ
îáðàáîòêà
Fork/Join: Çàäà÷è ñ ðåêóðñèâíîé ñòðóêòóðîé
Âåêòîðíûå ìîäåëè: huge-scale SIMD
Êîíâåéåð / data ow
. . .
Concurrency:
Message-passing (actor model)
Event loop (message-passing ñ îäíèì / íåñêîëüêèìè
îäèíàêîâûìè àêòîðàìè)
ÑåðâåðàD áîëüøèíñòâî q…sEáèáëèîòåêD â òF÷F ƒwing
Software Transactional Memory
Àñèíõðîííîå ïðîãðàììèðîâàíèå
93. Fork/Join
Ïðèìåð: Óìíîæåíèå ìàòðèö: C+ = AB (Â ò.÷. ïîèñê ïóòåé â
ãðàôàõ è ò.ï.)
A è B ìàëû ⇒ âëîá
Fork: Ïîäåëèòü A íà âåðõ/íèç è B íà ëåâî/ïðàâî
Join: Íè÷åãî, ïðîñòî äîæäàòüñÿ ðåçóëüòàòîâ Fork
95. Fork/Join in JDK7
Ïðèìåðíî òàê. Îôèöèàëüíîãî îêîí÷àòåëüíîãî Javadoc äî ñèõ
ïîð íåò.
class Solver extends RecursiveAction {
private final Problem problem;
int result;
protected void compute() {
if (problem.size THRESHOLD) {
result = problem.solveSequentially();
} else {
int m = problem.size / 2;
Solver left, right;
left = new Solver(problem.subProblem(0, m));
right = new Solver(problem.subProblem(m, problem.size));
forkJoin(left, right);
result = //get the result from left right
}
}
}
ForkJoinExecutor pool = new ForkJoinPool(
Runtime.availableProcessors());
Solver solver = new Solver(new Problem());
pool.invoke(solver);
96. Âåêòîðíûå àëãîðèòìû
Huge-scale SIMD: Ïðèìèòèâíûå îïåðàöèè îïåðèðóþò ñðàçó íàä
áîëüøèìè ìàññèâàìè.
Map: Ïðèìåíåíèå ôóíêöèè ê êàæäîìó ýëåìåíòó / ñêëåéêà
N ìàññèâîâ ïî N-àðíîé îïåðàöèè
Fold: Àññîöèàòèâíàÿ ñâåðòêà â ìîíîèäå.
àññîöèàòèâíà: a (b c) = (a b) c
u åäèíèöà : a u = u a = a
fold u [x0, x1, . . . , xn] = u x0 x1 . . . xn
Scan (Prex sum): Ïðîáåã (Ïðåôèêñíàÿ ñóììà)
scan u [x0, x1, . . . , xn] = [u, u x0, u x0 x1, . . . , u . . . xn]
98. Ïðåôèêñíûå ñóììû
×òî ìîæíî ñäåëàòü ñâåðòêîé/ïðîáåãîì (ò.å. ïàðàëëåëüíî):
sum,min,max,avg,. . .
Radix sort, Quicksort
Ñëîæåíèå äëèííûõ ÷èñåë
Âûïóêëàÿ îáîëî÷êà
Ìíîãèå àëãîðèòìû íà ãðàôàõ
Ìíîãèå ðåêóððåíòíûå ïîñëåäîâàòåëüíîñòè n-ãî ïîðÿäêà
Òðåõäèàãîíàëüíûå ñèñòåìû óðàâíåíèé
. . .
99. Ïðåôèêñíûå ñóììû
Îñîáåííî èíòåðåñíî, êàê ýòî äåëàåòñÿ. Áàçîâûå îïåðàöèè
ïîâåðõ ïðîáåãà:
Ðåêóððåíòíàÿ ïîñëåäîâàòåëüíîñòü 1ãî ïîðÿäêà
Óïàêîâêà ìàññèâà
Ñîðòèðîâêà ìàññèâà ïî 1-áèòíîìó ôëàãó (ðàçáèåíèå)
Ñåãìåíòèðîâàííûé ïðîáåã (ïðîáåã ñî ñáðîñàìè)
103. Ïðåôèêñíûå ñóììû
 öåëîì êðàñèâûé, ìîùíûé, ïðîñòîé â ðåàëèçàöèè è
íåîáû÷íûé âåêòîðíûé ÿçûê.
×àñòî èñïîëüçóþò íà GPU.
http://sourceforge.net/projects/amino-cbbs/ ðåàëèçàöèÿ íà
t—v— @ñîäåðæèò ìíîãî äðóãèõ ãîòîâûõ ïàðàëëåëüíûõ àëãîðèòìîâAF
http://www.cs.cmu.edu/~blelloch/papers/Ble93.pdf ñòàòüÿ
€re(x sums —nd their —ppli™—tionsX îáçîð òåõíèê è ïðèìåíåíèéF
http://www.cs.cmu.edu/~blelloch/papers/Ble90.pdf †e™tor
models for d—t—Ep—r—llel ™omputingD öåëàÿ êíèãà ïðî òî æåF Ñòðîæàéøå
ðåêîìåíäóþF
104. ParallelArray
New in JDK7. Ðåàëèçàöèÿ íåêîòîðûõ âåêòîðíûõ ïðèìèòèâîâ
ïîâåðõ Fork/Join framework.
Ñòàíäàðòíûå: Map, Zip, Filter, Fold (reduce), Scan
(cumulate + precumulate), Sort
Ïîèíòåðåñíåå: Ñå÷åíèå ïî äèàïàçîíó (withBounds),
Ïåðåñòàíîâêà (replaceWithMappedIndex)
Ôóíêöèîíàëüíûé äî ìîçãà êîñòåé API (ïîäàâëÿþùåå
áîëüøèíñòâî ôóíêöèé ÔÂÏ)
ÏðàâäàD áåç ôàíàòè÷íîãî ñëåäîâàíèÿ ôóíêöèîíàëüíîé
÷èñòîòå
Ëåíèâûå îïåðàöèè
Ñïëàâêà îïåðàöèé (fusion)
105. ParallelArray
Ïðèìåð÷èê.
ParallelArrayStudent students = new ParallelArrayStudent(fjPool, data);
double bestGpa = students.withFilter(isSenior)
.withMapping(selectGpa)
.max();
public class Student {
String name;
int graduationYear;
double gpa;
}
static final Ops.PredicateStudent isSenior = new Ops.PredicateStudent() {
public boolean op(Student s) {
return s.graduationYear == Student.THIS_YEAR;
}
};
static final Ops.ObjectToDoubleStudent selectGpa = new Ops.ObjectToDoubleStudent() {
public double op(Student student) {
return student.gpa;
}
};
106. Message-passing concurrency
Ôàêòè÷åñêè åäèíñòâåííûé ïîäõîä â ðàñïðåäåëåííûõ ñèñòåìàõ.
Âîîáùå íåò ðàçäåëÿåìîãî ñîñòîÿíèÿ
Àêòîðû îáìåíèâàþòñÿ ñîîáùåíèÿìè
Ó êàæäîãî àêòîðà åñòü mailbox (FIFO-î÷åðåäü ñîîáùåíèé)
Îòñûëêà ñîîáùåíèé àñèíõðîííàÿ è íåáëîêèðóþùàÿ
108. Message-passing concurrency
Ðåàëèçàöèè:
Êó÷à ÿçûêîâ: MPI
Termite Scheme
Clojure: agents
Î÷åíü èíòåðåñíàÿ è ìîùíàÿ âàðèàöèÿF he(nitely worth
seeingF http://clojure.org/agents
glojure is to ™on™urrent progr—mming —s t—v— w—s to yy€
Scala: actors
Java: Kilim
Haskell: CHP (Communicating Haskell Processes)
È, êîíå÷íî, Erlang
uiller fe—tureX ƒele™tive re™eive
111. Event loop
Âàðèàöèÿ íà òåìó message passing, íî íå ìíîãî
âçàèìîäåéñòâóþùèõ àêòîðîâ, à îäèí (èëè íåñêîëüêî
îäèíàêîâûõ) æèðíûé è âñåìîãóùèé.
Ñåðâåðû (è accept, è select/poll/... ñþäà îòíîñÿòñÿ)
GUI-ôðåéìâîðêè
Ïðåëåñòè:
Ýòî íå ôðåéìâîðê, íî ïàòòåðí: ëåãêî ðåàëèçîâàòü è
èñïîëüçîâàòü äàæå íà ìèêðîóðîâíå
Ê íåìó ñâîäèòñÿ êó÷à çàäà÷
Î÷åíü ëåãêî ïèøåòñÿ
Áîëüøèíñòâî ìíîãîïîòî÷íûõ ïðîáëåì îòñóòñòâóþò
113. Software Transactional Memory
Òðàíçàêöèè íà óðîâíå ïàìÿòè; àòîìàðíûå êóñêè êîäà.
Ïîëíîöåííûé commit/rollback, ïîëíàÿ àòîìàðíîñòü
Òðàíçàêöèè ïîâòîðÿåìû
retry ïðè êîììèòåD åñëè èçâíå èçìåíåíà ïðî÷òåííàÿ
ïåðåìåííàÿ
Òðàíçàêöèîííûå ïðîãðàììû êîìáèíèðóåìû!
 îòëè÷èå îò sh—red st—te
@ïðàâèëüíîCïðàâèëüíî=ïðàâèëüíîA
Íå äîëæíî áûòü íèêàêèõ ïîáî÷íûõ ýôôåêòîâ, êðîìå
îáðàùåíèé ê òðàíçàêöèîííîé ïàìÿòè
115. Software Transactional Memory
Ïñåâäîêîä (âïåðâûå ïðåäëîæåíî â ðåàëèçàöèè â Haskell):
atomic {
if (queueSize 0) {
remove item from queue and use it
} else {
retry
}
}
retry ïåðåçàïóñêàåò òðàíçàêöèþ â ìîìåíò, êîãäà èçìåíèòñÿ
îäíà èç ïðî÷èòàííûõ åþ ïåðåìåííûõ.
116. Software Transactional Memory
Ðåàëèçàöèè:
Haskell: ïîëíîöåííàÿ è áåçîïàñíàÿ ïîääåðæêà
Clojure: ïîëíîöåííàÿ è íåáåçîïàñíàÿ ïîääåðæêà
Java: Deuce, JSTM, . . .
Ìíîãî áèáëèîòåê äëÿ C è C++, â ò.÷. äàæå êîìïèëÿòîðû ñ
êëþ÷åâûì ñëîâîì atomic
Íå çíàþD èñïîëüçóþò ëè èõ
117. Software Transactional Memory
Further reading:
http://research.microsoft.com/Users/simonpj/papers/stm/
stm.pdf gompos—˜le wemory „r—ns—™tionsF
http:
//themonadreader.files.wordpress.com/2010/01/issue15.pdf
Æóðíàë won—dF‚e—der sssue ISD ñîäåðæèò ñòàòüþ smplementing ƒ„w
in pure r—skellD èíòåðåñíîå îáñóæäåíèå âîïðîñîâ ðåàëèçàöèè ƒ„wF
120. Àñèíõðîííîå ïðîãðàììèðîâàíèå
Ïðè÷èíû:
Áëîêèðóþùèå âûçîâû íåóäîáíû èëè íå ïîääåðæèâàþòñÿ
eteˆ
q…s @
”
àñèíõðîííî ïîëó÷èòü ðåçóëüòàò äèàëîãà“ è òFïFA
Àñèíõðîííûé API äîïóñêàåò áîëåå ýôôåêòèâíóþ
ðåàëèçàöèþ
Àñèíõðîííûé ââîäEâûâîä
Àñèíõðîííûé äîñòóï ê õðàíèëèùàì äàííûõ F F F
Àêòèâíàÿ ñòîðîíà @ñåðâåðD ñåòåâîé äðàéâåð ÎÑ F F F A ìîæåò
ðåøàòüD êîãäà è â êàêîì ïîðÿäêå îòâå÷àòü íà çàïðîñû
121. Àñèíõðîííîå ïðîãðàììèðîâàíèå
Ïðîáëåìû:
Íåëèíåéíûé ïîòîê èñïîëíåíèÿ
Î÷åíü íåóäîáíî îòëàæèâàòü
Ïîøàãîâîå âûïîëíåíèå â îòëàä÷èêå íå ðàáîòàåò
Íåò àíàëîãîâ ïðèâû÷íûõ êîíñòðóêöèé óïðàâëåíèÿ (öèêëû,
try..finally . . . )
Äàæå ñýìóëèðîâàòü èõ íåëåãêî
 áîëüøèíñòâå ßÏ àñèíõðîííûé êîä êðàéíå ãðîìîçäîê
122. Àñèíõðîííîå ïðîãðàììèðîâàíèå
public void requestInit() {
AdminConsoleService.App.getInstance().getLoadGeneratorServersInfo(
new AcAsyncCallbackListServerInfo() {
public void doOnSuccess(final ListServerInfo loadGenerators) {
AdminConsoleService.App.getInstance().getApplicationServersInfo(
new AcAsyncCallbackListServerInfo() {
public void doOnSuccess(ListServerInfo appServers) {
init(appServers, loadGenerators);
}
});
}
});
}
(c) ru_java.
124. Àñèíõðîííîå ïðîãðàììèðîâàíèå
Êàê æå áûòü? Âñïîìèíàåì óðîêè ôóíêöèîíàëüíîãî
ïðîãðàììèðîâàíèÿ.
Èçáàâèòüñÿ îò ñèíòàêñè÷åñêîãî ìóñîðà
Àñèíõðîííûå çíà÷åíèÿ ïåðâîêëàññíûå îáúåêòû @ñìF
äàëååA
Íóæåí ÿçûê ñ çàìûêàíèÿìèF ƒorry guysF
Ðåàëèçîâàòü ñòðóêòóðû óïðàâëåíèÿ
Íå ñîéòè ñ óìà îò ñëîæíîñòè
125. Àñèíõðîííîå ïðîãðàììèðîâàíèå
Êàê æå áûòü? Âñïîìèíàåì óðîêè ôóíêöèîíàëüíîãî
ïðîãðàììèðîâàíèÿ.
Èçáàâèòüñÿ îò ñèíòàêñè÷åñêîãî ìóñîðà
Ðåàëèçîâàòü ñòðóêòóðû óïðàâëåíèÿ
Öèêëû ÷åðåç ðåêóðñèþ
Ýìóëÿöèÿ õâîñòîâûõ âûçîâîâ
Âñå ýòî ñòîèò àáñòðàãèðîâàòü â
”
êîìáèí¡àòîðíóþ
áèáëèîòåêó“
Íå ñîéòè ñ óìà îò ñëîæíîñòè
126. Àñèíõðîííîå ïðîãðàììèðîâàíèå
Êàê æå áûòü? Âñïîìèíàåì óðîêè ôóíêöèîíàëüíîãî
ïðîãðàììèðîâàíèÿ.
Èçáàâèòüñÿ îò ñèíòàêñè÷åñêîãî ìóñîðà
Ðåàëèçîâàòü ñòðóêòóðû óïðàâëåíèÿ
Íå ñîéòè ñ óìà îò ñëîæíîñòè
Öåëûé êëàññ ïðîáëåìD ñïåöèôè÷íûõ äëÿ ýòîãî ïîäõîäà
Áîëüøèíñòâî ñâÿçàíî ñ mut—˜le st—te
128. Àñèíõðîííîå ïðîãðàììèðîâàíèå
Ó÷èìñÿ ó .NET âîîáùå è F# â ÷àñòíîñòè.
let AsyncHttp(url:string) =
async { // Create the web request object
let req = WebRequest.Create(url)
// Get the response, asynchronously
let! rsp = req.GetResponseAsync()
// Grab the response stream and a reader. Clean up when we're done
use stream = rsp.GetResponseStream()
use reader = new System.IO.StreamReader(stream)
// synchronous read-to-end
return reader.ReadToEnd() }
Ýòî íàçûâàåòñÿ
”
asynchronous workows“.
Workow êðàñèâûé ñèíîíèì äëÿ ñëîâà
”
Ìîíàäà“
(google://workow, monad).
http://blogs.msdn.com/dsyme/archive/2007/10/11/
introducing-f-asynchronous-workflows.aspx
129. Àñèíõðîííîå ïðîãðàììèðîâàíèå
class AsyncPrimitives {
AsyncT succeed(T value) {...}
AsyncT failwith(Throwable error) {...}
AsyncU bind(AsyncT at, FuncT,AsyncU fau) {...}
}
Ýòîãî äîñòàòî÷íî äëÿ áîëüøèíñòâà ñòðóêòóð óïðàâëåíèÿ
3.
Ýòî íàçûâàåòñÿ
”
ìîíàäà“.
3
Ïðè ïîääåðæêå îïòèìèçàöèè õâîñòîâûõ âûçîâîâ
130. Àñèíõðîííîå ïðîãðàììèðîâàíèå
Ìîíàäû ïðîíèêëè â ìåéíñòðèì: ó C# òåïåðü òîæå ó÷èìñÿ
(LINQ).
var requests = new[]
{
WebRequest.Create(http://www.google.com/),
WebRequest.Create(http://www.yahoo.com/),
WebRequest.Create(http://channel9.msdn.com/)
};
http://www.aboutcode.net/2008/01/14/Async+WebRequest+
Using+LINQ+Syntax.aspx
131. Àñèíõðîííîå ïðîãðàììèðîâàíèå
Ìîíàäû ïðîíèêëè â ìåéíñòðèì: ó C# òåïåðü òîæå ó÷èìñÿ
(LINQ).
var pages = from request in requests
select
from response in request.GetResponseAsync()
let stream = response.GetResponseStream()
from html in stream.ReadToEndAsync()
select new { html, response };
http://www.aboutcode.net/2008/01/14/Async+WebRequest+
Using+LINQ+Syntax.aspx
132. Àñèíõðîííîå ïðîãðàììèðîâàíèå
Ìîíàäû ïðîíèêëè â ìåéíñòðèì: ó C# òåïåðü òîæå ó÷èìñÿ
(LINQ).
foreach (var page in pages)
{
page(d =
{
Console.WriteLine(d.response.ResponseUri.ToString());
Console.WriteLine(d.html.Substring(0, 40));
Console.WriteLine();
});
}
http://www.aboutcode.net/2008/01/14/Async+WebRequest+
Using+LINQ+Syntax.aspx
ÌîðàëüX Ïîçíàéòå ìîíàäû ñòàíåò ëåã÷å ïèñàòü àñèíõðîííûé êîäF
133. Àñèíõðîííîå ïðîãðàììèðîâàíèå
Further reading:
Î÷åíü èíòåðåñíûé ïîäõîä ñ èñïîëüçîâàíèåì yield return:
http://tomasp.net/blog/csharp-async.aspxF
‡es hyer îáúÿñíåíèå ìîíàäû gont íà g5X http://blogs.msdn.
com/wesdyer/archive/2008/01/11/the-marvels-of-monads.aspx
×òî òàêîå êîìáèíàòîðíàÿ áèáëèîòåêàX
http://fprog.ru/2009/issue3D ñòàòüÿ
”
Ýëåìåíòû ôóíêöèîíàëüíûõ
ÿçûêîâ“
Àñèíõðîííûå êîìáèíàòîðû íà t—v—X
http://spbhug.folding-maps.org/wiki/EugeneKirpichovD
ñëàéäû ïðî t—v— è p€F
134. Further reading
Ðàçíûå ïàòòåðíû ìíîãîïîòî÷íîãî è ðàñïðåäåëåííîãî
ïðîãðàììèðîâàíèÿ. Î÷åíü ìíîãî è èíòåðåñíî.
http://www.cs.wustl.edu/~schmidt/patterns-ace.html
http:
//parlab.eecs.berkeley.edu/wiki/patterns/patterns
åùå êðó÷å
136. Cutting edge
×òî óìååò Haskell:
Âñå ïîáî÷íûå ýôôåêòû êîíòðîëèðóþòñÿ
Íåò íåêîíòðîëèðóåìûõ ïðîáëåì èç-çà èõ íàëè÷èÿ
Ïîçâîëÿåò íåìûñëèìûå â äðóãèõ ÿçûêàõ âåùè
137. Cutting edge
×òî óìååò Haskell:
Ñàìûå áûñòðûå â ìèðå ëåãêîâåñíûå íèòè è ïðèìèòèâû
ñèíõðîíèçàöèè
I ìåñòî íà v—ngu—ge ƒhootoutD THx áûñòðåå íàòèâíûõ
…˜untuD Sõ áûñòðåå irl—ng3
Ïàðàëëåëüíûå ñòðàòåãèè
Ïðîñòûå ïàðàëëåëüíûå âû÷èñëåíèÿX íåò àíàëîãîâ â äðóãèõ
ÿçûêàõ
Data Parallel Haskell
Àâòîìàòè÷åñêè ðàñïàðàëëåëèâàåìûå âåêòîðíûå
âû÷èñëåíèÿ
Òðàíçàêöèîííàÿ ïàìÿòü
Ðàáîòà â íàïðàâëåíèè GPU
Ìîùíûå áèáëèîòåêè
139. Ïàðàëëåëüíûå ñòðàòåãèè
Ëåíèâîñòü ïîçâîëÿåò îòäåëèòü àëãîðèòì è ñïîñîá
ðàñïàðàëëåëèâàíèÿ.
Ðåçóëüòàò àëãîðèòìà ñòðóêòóðà, ïîëíàÿ
”
îáåùàíèé“.
Îáåùàíèÿ
”
èñïîëíÿþòñÿ“ (ôîðñèðóþòñÿ) ñ ïîìîùüþ
ñòðàòåãèè.
Ñòðàòåãèÿ ýòî îáûêíîâåííàÿ, ïðîñòàÿ ôóíêöèÿ.
Èäåÿ ÿäåðíàÿ. Ýòî ìîæíî ðåàëèçîâàòü è íà Java, åñëè
141. Data Parallel Haskell
Âåêòîðèçàòîð (òðàíñëèðóåò äàæå ðåêóðñèâíûå ôóíêöèè â
âåêòîðíûå îïåðàöèè)
Áèáëèîòåêà ïàðàëëåëüíûõ âåêòîðíûõ îïåðàöèé
dotp_double :: [:Double:] - [:Double:] - Double
dotp_double xs ys = sumP [:x * y | x - xs | y - ys:]
smMul :: [:[:(Int,Float):]:] - [:Float:] - Float
smMul sm v = sumP [: svMul sv v | sv - sm :]
http://research.microsoft.com/en-us/um/people/simonpj/
papers/ndp/NdpSlides.pdf ñëàéäû
142. Data Parallel Haskell
sort :: [:Float:] - [:Float:]
sort a = if (length a = 1) then a
else sa!0 +++ eq +++ sa!1
where
m = a!0
lt = [: f | f-a, fm :]
eq = [: f | f-a, f==m :]
gr = [: f | f-a, fm :]
sa = [: sort a | a - [:lt,gr:] :]
Âåêòîðèçóåòñÿ è ïàðàëëåëèçóåòñÿ.
143. Repa
Regular, shape-polymorphic, parallel arrays in Haskell.
The Haskell code transparently makes use of multicore hardware
Ñäåëàíî ãðóïïîé Ìàíóýëÿ ×àêðàâàðòè ýòî îäèí èç
êðóòåéøèõ èìïëåìåíòîðîâ Õàñêåëëà.
http://justtesting.org/
regular-shape-polymorphic-parallel-arrays-in
145. Òðàíçàêöèîííàÿ ïàìÿòü
check True = return ()
check False = retry
limitedWithdraw :: Account - Int - STM ()
limitedWithdraw acc amount = do
bal - readTVar acc
check (amount = 0 || amount = bal)
writeTVar acc (bal - amount)
×åòêîå ðàçäåëåíèå ìåæäó:
IO êîä ñ ïðîèçâîëüíûìè ïîáî÷íûìè ýôôåêòàìè
STM êîä, åäèíñòâåííûé ýôôåêò êîòîðîãî ðàáîòà ñ
òðàíçàêöèîííîé ïàìÿòüþ
atomically :: STM t - IO t (íàîáîðîò íåëüçÿ)
146. Erlang
Ñâÿçü ïðîöåññîâ òîëüêî ÷åðåç îáìåí ñîîáùåíèÿìè.
Selective receive (èçáèðàòåëüíàÿ âûáîðêà èç mailbox).
Ìîùíàÿ ôè÷àF
Ïðîçðà÷íàÿ ðàñïðåäåëåííîñòü.
Î÷åíü ýôôåêòèâíàÿ ðåàëèçàöèÿ íèòåé è message passing.
Î÷åíü êðóòàÿ è ïðîäóìàííàÿ èíôðàñòðóêòóðà.
Î÷åíü ïðîñòîé ÿçûê.
Àêòèâíî ïðèìåíÿåòñÿ â èíäóñòðèè (â ò.÷. Amazon,
Facebook, Yahoo, . . . ).
http://spbhug.folding-maps.org/wiki/Erlang ñàìîïèàð YA
150. Parallel LINQ (PLINQ)
IEnumerableT data = ...;
var q = from x in data.AsParallel()
where p(x)
orderby k(x)
select f(x);
foreach (var e in q) a(e);
Òðàíñëèðóåòñÿ â êîìáèíàöèþ
ParallelEnumerable.{Select,Where,OrderBy} è ò.ï.
152. Clojure
Clojure is to concurrent programming as Java was to OOP
Áèáëèîòåêà ÷èñòî ôóíêöèîíàëüíûõ ñòðóêòóð äàííûõ
4 ìåõàíèçìà concurrency: Atoms, Vars, Agents, Refs
Âñå îíè îïåðèðóþò íàä immutable çíà÷åíèÿìè è
÷èñòûìè ôóíêöèÿìè
fe™—use this is the w—y to goF
153. Atoms
Áîëåå èëè ìåíåå îáû÷íûå atomic ïåðåìåííûå.
(swap! atom f)
”
Àòîìàðíî çàìåíèòü x íà f (x), âåðíóòü
ñòàðûé x (compare-and-exchange)“
f îáÿçàíà áûòü ÷èñòîé: åå ìîãóò âûçâàòü
íåñêîëüêî ðàç
http://clojure.org/atoms
154. Vars
Thread-local, dynamically scoped ïåðåìåííûå.
(def x 0) îáúÿâèòü x ñ ãëîáàëüíûì çíà÷åíèåì ïî
óìîë÷àíèþ 0.
x ïðî÷èòàòü çíà÷åíèå x.
(set! x 5) ïðèñâîèòü x = 5 â ðàìêàõ òåêóùåé íèòè.
(binding [x 5] (do-something)) âûïîëíèòü do-something,
ïîëàãàÿ x = 5 â ðàìêàõ òåêóùåé íèòè.
http://clojure.org/vars
155. Agents
Àñèíõðîííî èçìåíÿåìûå ïåðåìåííûå.
(agent 0) àãåíò ñ íà÷àëüíûì çíà÷åíèåì 0
(deref x) òåêóùåå çíà÷åíèå
(send x f) àñèíõðîííî çàìåíèòü x íà f (x)
(await x) äîæäàòüñÿ îêîí÷àíèÿ âñåõ äåéñòâèé íàä àãåíòîì
(set-validator x f) ïîâåñèòü âàëèäàòîð ñîñòîÿíèÿ
(add-watch x f) ïîâåñèòü ñëóøàòåëÿ
http://clojure.org/agents
156. Refs
Òðàíçàêöèîííàÿ ïàìÿòü (STM).
Äîâîëüíî îáû÷íàÿ
Òðàíçàêöèè äîëæíû áûòü áåç ïîáî÷íûõ ýôôåêòîâ
Ëþáîïûòíî: (commute x f): çàìåíèòü x íà f (x),
ïðåäïîëàãàÿ ÷òî f êîììóòèðóåò ñ îñòàëüíûìè.
ÍàïðèìåðD (commute counter inc) ïîäîéäåò
Ðàáîòàåò ñëåãêà áûñòðååD ÷åì äðóãèå ôóíêöèèEìóòàòîðû
http://clojure.org/refs
158. ×òî áûëî
Êëàññèôèêàöèÿ ìíîãîïîòî÷íûõ ïðîãðàìì
Ôîðìàëüíûå ìåòîäû (LTL) è òóëû (SPIN,JPF,CheckThread)
Êîððåêòíîñòü: èíêàïñóëÿöèÿ, âûñîêîóðîâíåâûå îïåðàöèè,
ôàêòîðèçàöèÿ, äåäëîêè, àòîìàðíûå è èäåìïîòåíòíûå
îïåðàöèè, îòðèöàòåëüíàÿ îáðàòíàÿ ñâÿçü
Ìåòîäèêè: fork/join, âåêòîðíûå àëãîðèòìû,
message-passing, event-driven, STM, àñèíõðîííîå
ïðîãðàììèðîâàíèå
Haskell: ëåãêèå íèòè, ïàðàëëåëüíûå ñòðàòåãèè,
âåêòîðèçàöèÿ, STM
Erlang: ìîùíàÿ èíôðàñòðóêòóðà
Clojure: Atoms, Vars, Agents, Refs
C#: PLINQ
161. Java Memory Model
Ãðóáî: Íàáîð àêñèîì î òîì, êàêèå ïðîèñøåñòâèÿ â ïàìÿòè êîìó
è êîãäà âèäèìû.
×òîáû êîìïèëÿòîð ìîã âûïîëíÿòü îïòèìèçàöèè
Ïåðåóïîðÿäî÷åíèåD óäàëåíèå äîõëîãî êîäà F F F
×òîáû ìîæíî áûëî ýôôåêòèâíî èñïîëüçîâàòü êýøè,
îñîáåííî â ìíîãîïðîöåññîðíûõ ñèñòåìàõ.
162. Ïðèìåð
private int x, y;
void foo() {
x = 5;
y = 7;
}
void bar() {
if(x==5) {
// Íåâåðíî, ÷òî y==7
}
}
163. nal ïîëÿ è JMM
Ïðèìåð
public final class Foo {
private int x;
Foo(int x) {this.x = x;}
int getX() {return x; }
}
Íå thread-safe! x äîëæåí áûòü nal.
164. Java Memory Model
Áîëåå òî÷íî: Íàáîð àêñèîì î òîì, êàêèå íàáëþäåíèÿ
ðåçóëüòàòîâ ïîñëåäîâàòåëüíîñòè äåéñòâèé â ïàìÿòè
âîçìîæíû.
Öåëè:
Áåçîïàñíîñòü
Áåçîïàñíàÿ èíèöèàëèçàöèÿ
Èíòóèòèâíîñòü
Ýôôåêòèâíàÿ ðåàëèçóåìîñòü
166. Java Memory Model
Îñíîâíûå ïîíÿòèÿ:
Äåéñòâèå
Îáðàùåíèå ê ðàçäåëÿåìûì ïåðåìåííûì
ÂõîäGâûõîä èç ìîíèòîðà
ÇàïóñêGîæèäàíèå íèòåé
Âèäèìîñòü
Îòíîøåíèå happens-before
Æèçíü I íèòè óïîðÿäî÷åíà
Æèçíü I ìîíèòîðà óïîðÿäî÷åíà
Æèçíü I vol—tile ïåðåìåííîé óïîðÿäî÷åíà
167. ×òî âñå-òàêè äåëàåò volatile?
×òåíèå îäíîé volatile ïåðåìåííîé ïî÷òè òî÷êà
ñèíõðîíèçàöèè.
class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42; v = true;
}
public void reader() {
if (v == true) { /* x==42 */ }
}
}
168. ×òî âñå-òàêè äåëàåò nal?
Ïîñëå êîíñòðóèðîâàíèÿ final ïîëÿ âèäèìû.
Âèäèìû òàêæå îáúåêòû, äîñòóïíûå ÷åðåç íèõ
Ññûëêà íà îáúåêò íå äîëæíà óòåêàòü èç êîíñòðóêòîðà
Ðåãèñòðàöèÿ ëèñòåíåðîìD ïðèñâàèâàíèå ñòàòè÷åñêîãî
ïîëÿFFF
Äåëàéòå ýòî ïîñëå êîíñòðóèðîâàíèÿF
171. Óìåíüøåíèå áëîêèðîâîê
Êàê íå æäàòü?
Èñïîëüçîâàòü íåáëîêèðóþùèå àëãîðèòìû è îïåðàöèè
Óâåëè÷èòü ãðàíóëÿðíîñòü áëîêèðîâîê
ÀíòîíèìX Îäèí ìîíèòîð íà âñþ ïðîãðàììó
Èñïîëüçîâàòü àëãîðèòìû, áëîêèðóþùèå íå âñåõ
‚e—der‡ritervo™k
172. Íåáëîêèðóþùèå àëãîðèòìû è îïåðàöèè
Áàçèñ:
get, set, getAndSet
boolean compareAndSet(expect, update) (CAS)
Ïîìåíÿòü ñ expect íà upd—te
Åñëè íå expe™t çíà÷èòD ìû ïðîçåâàëèD êàê êòîEòî
ïîìåíÿë èç äðóãîé íèòè
Íàäî ïåðåçàïóñòèòü êóñîê àëãîðèòìà â íàäåæäåD ÷òî òåïåðü
îáîéäåòñÿ áåç êîëëèçèé
addAndGet, getAndAdd, . . .
173. Íåáëîêèðóþùèå àëãîðèòìû è îïåðàöèè
Ñðåäñòâà â Java:
java.util.concurrent.atomic
AtomicInteger, AtomicLong
AtomicReference, AtomicStampedReference
(ìàëîèçâåñòíî) AtomicIntegerArray, Long, Reference
174. Àòîìàðíûå îïåðàöèè
Ïðèìåð àëãîðèòìà íà CAS:
public class ConcurrentStackE {
AtomicReferenceNodeE head = new AtomicReferenceNodeE();
public void push(E item) {
NodeE newHead = new NodeE(item);
NodeE oldHead;
do {
oldHead = head.get();
newHead.next = oldHead;
} while (!head.compareAndSet(oldHead, newHead));
}
public E pop() {
...
}
}
http://www.ibm.com/developerworks/java/library/j-jtp04186/
index.html
177. Óìåíüøåíèå ãðàíóëÿðíîñòè áëîêèðîâîê
Áëîêèðóéòå íå âñ¼:
Åñëè íàäî çàùèòèòü áîëüøóþ ñòðóêòóðó äàííûõ, íî ìåíÿþòñÿ
òîëüêî åå êóñêè çàùèùàéòå êóñêè èëè ãðóïïû êóñêîâ.
Ïðèìåð: ConcurrentHashMap (new in JDK6). Òåõíèêà lock
striping.
×òåíèå íåáëîêèðóþùåå
Çàïèñü áëîêèðóþùàÿ â 1/k ñëó÷àåâ, ãäå k íàñòðàèâàåòñÿ
Ðåêîìåíäóåòñÿ k ≈ ÷èñëî íèòåéEïèñàòåëåé
k áëîêèðîâîê çàùèùàþò k êóñêîâ õýø-òàáëèöû
Èòåðàòîðû òàêæå íå áðîñàþò CME
178. Reader/Writer lock
Áëîêèðóéòå íå âñåõ:
×òåíèå ñîâìåñòèìî ñ ÷òåíèåì, íî íå ñ çàïèñüþ.
Áûâàþò ðàçíûå:
Readers-preference
Writers-preference
Arrival-order
. . .
Êëàññ ReentrantReadWriteLock. Ðåàëèçóåò ïðèìåðíî
arrival-order. Åñëè åñòü æäóùèé ïèñàòåëü íîâûå ÷èòàòåëè
òîëüêî ïîñëå íåãî.
181. Öèôðû
Ñêîëüêî ðåàëüíî ñòîÿò ðàçëè÷íûå îïåðàöèè?
Àòîìàðíûå îïåðàöèè ≈ 0.1ìêñ; incAndGet
è volatile 2-3x áûñòðåå CAS
Ïåðåêëþ÷åíèå êîíòåêñòà Íåñêîëüêî ìêñ
(íåçàâèñèìî îò ÷èñëà íèòåé)
Uncontended synchronized ≈ 0.1-1ìêñ
Contented synchronized ≈ 20ìêñ
http://mailinator.blogspot.com/2008/03/
how-fast-is-java-volatile-or-atomic-or.html ñðàâíåíèå
ñêîðîñòè ðàçëè÷íûõ ñïîñîáîâ ñèíõðîíèçàöèè
182. ×òî óìååò JVM?
Biased locking
Lock coarsening
Lock elision (escape analysis)
http:
//www.infoq.com/articles/java-threading-optimizations-p1
ho t—v— thre—ding optimiz—tions —™tu—lly workc
183. ×òî óìååò JVM?
Biased locking (new in 1.5.0_6):
Áîëüøèíñòâî îáúåêòîâ çà âñþ æèçíü áëîêèðóåò òîëüêî 1
íèòü
Äåëàåòñÿ òàê, ÷òîáû äëÿ ýòîé íèòè ñèíõðîíèçàöèÿ áûëà
î÷åíü áûñòðîé (äàæå áåç CAS)
-XX:+UseBiasedLocking (ïî óìîë÷àíèþ âêëþ÷åíî
íà÷èíàÿ ñ Java SE 6)
http://tinyurl.com/biasedlocking îò ðàçðàáîò÷èêîâ t†wD
ïîEðóññêè
184. ×òî óìååò JVM?
Lock coarsening:
public void setupFoo(Foo foo) {
foo.setBarCount(1);
foo.setQuxEnabled(true);
foo.addGazonk(new Gazonk());
}
. . . è âñå 3 ìåòîäà synchronized.
Òóò íåçà÷åì äåëàòü synchronized 3 ðàçà. Ìîæíî çàïèõíóòü
âñå â 1 synchronized.
Îïöèÿ -XX:+EliminateLocks (ïî óìîë÷àíèþ âêëþ÷åíî).
http://citeseer.ist.psu.edu/459328.html ñòàòüÿ ïðî òåõíèêóF
185. ×òî óìååò JVM?
Escape analysis: Åñëè îáúåêò íå óáåãàåò â äðóãóþ íèòü, òî íåò
ñìûñëà äåëàòü íà íåì synchronized.
DeepThought dt = new DeepThought();
dt.turnOnPower();
dt.enterData(data);
dt.wakeup();
return dt.computeUltimateAnswer();
Îïöèÿ -XX:+DoEscapeAnalysis.
186. Òåñòèðîâàíèå
Òåñòèðîâàòü ìíîãîïîòî÷íûé êîä àäñêè ñëîæíî.
Ïðîòåñòèðîâàòü ïðàâèëüíîñòü äåòåðìèíèðîâàííîãî êîäà
ìîæíî, õîòü è òðóäíî
Ïðîòåñòèðîâàòü îòñóòñòâèå áàãîâ, ñâÿçàííûõ ñ
íåäåòåðìèíèçìîì ñîâñåì ñëîæíî
Íåò êîíòðîëÿ íàä ãëàâíûì ôàêòîðîì òðóäíîóëîâèìûõ
îøèáîê íåäåòåðìèíèçìîì øåäóëåðà
Íåîáõîäèìî ñòðåññ-òåñòèðîâàíèå
È äàæå îíî íè÷åãî íå ãàðàíòèðóåò
Ëó÷øåD êîíå÷íîD äîêàçûâàòü êîððåêòíîñòü
Îøèáêè âñå ðàâíî ïðîëåçóò. Èõ äîëæíî áûòü õîðîøî
âèäíî.
188. Íàëè÷èå îæèäàåìîãî ïîâåäåíèÿ
Êàê ïðîâåðèòü, ÷òî ìíîãîïîòî÷íûé êîä ðåàëèçóåò
îïðåäåëåííûé ïðîòîêîë â èäåàëüíûõ óñëîâèÿõ?
Ïîíàñòàâèòü çàäåðæåê, òåì ñàìûì ñäåëàâ ïîðÿäîê
ñîáûòèé äåòåðìèíèðîâàííûì
Ïðîâåðèòü, ÷òî ïðîèñõîäÿò íóæíûå ñîáûòèÿ â íóæíîì
ïîðÿäêå
ÏðîâåðÿòüD ÷òî áëîêèðóþùèå âûçîâû áëîêèðóþòñÿ
Èçìåðèòü äëèòåëüíîñòü èëè äîáàâèòü out-ïàðàìåòð
didBlock
ÏðîâåðÿòüD ÷òî íåáëîêèðóþùèå âûçîâû íå áëîêèðóþòñÿ
wo™k o˜je™tsD listeners âî âñåõ âàæíûõ òî÷êàõ êîäà
Êðèâî, äëèííî, óðîäëèâî, íî ðàáîòàåò.
189. Óñòîé÷èâîñòü ê íàãðóçêå
Êàê ïðîâåðèòü, ÷òî ìíîãîïîòî÷íûé êîä íå ëîìàåòñÿ ïîä
íàãðóçêîé?
Ïðèäóìàòü èíâàðèàíòû
Îðãàíèçîâàòü íàãðóçêó
Ïîñòîÿííî ïðîâåðÿòü èíâàðèàíòû
Äëèííî, óðîäëèâî, áåç ãàðàíòèé, íî ðàáîòàåò.
190. Óñòîé÷èâîñòü ê íàãðóçêå
Ïðèìåð: Òåñòèðóåì ConcurrentMap.
Èíâàðèàíò: Êàæäûé äîáàâëåííûé, íî íå óäàëåííûé
ýëåìåíò ïðèñóòñòâóåò â ìàïå
Èíâàðèàíò: size() ðàâíî ÷èñëó äîáàâëåííûõ, íî íå
óäàëåííûõ ýëåìåíòîâ.
191. Óñòîé÷èâîñòü ê íàãðóçêå
Ïðèìåð: Òåñòèðóåì ConcurrentMap
Ïîâòîðèòü 100000000000000 ðàç
Ñãåíåðèðîâàòü IHHHH ñëó÷àéíûõ çíà÷åíèéD ðàçáèòü íà IH
÷àñòåé ñëó÷àéíûì îáðàçîì
 IH íèòåéX
äîáàâëÿòü â ìàïó çíà÷åíèÿ èç i-é ÷àñòè ñî ñëó÷àéíûìè
íåáîëüøèìè çàäåðæêàìè
ïðîâåðÿòü, ÷òî âñå ïðåäûäóùèå çíà÷åíèÿ èç i-é ÷àñòè â
ìàïå åñòü
Ïî îêîí÷àíèè ïðîâåðèòü íàëè÷èå êàæäîãî çíà÷åíèÿ
Ïðèãîäèòñÿ CyclicBarrier
192. Ïîâòîðÿåìîñòü
Êàê ïîâòîðèòü ãîòîâóþ îøèáêó?
Íàïèñàòü äåëåãèðóþùèå mock-îáúåêòû, çàïèñûâàþùèå âñå
äåéñòâèÿ
Äîæäàòüñÿ îøèáêè
Íàïèñàòü mock-îáúåêòû, ïðîèãðûâàþùèå çàäàííûé
ñöåíàðèé
Ïîìîæåò íàéòè ãîíêè â ïðîòîêîëå. Íå ïîìîæåò íàéòè
íèçêîóðîâíåâûå ãîíêè (ìåæäó statement'àìè).
Áåç ìîçãîâ íå îáîéòèñü!
193. Êàê ñïðîâîöèðîâàòü îøèáêó
Êàê îðãàíèçîâàòü ìàêñèìóì íåäåòåðìèíèçìà øåäóëåðà?
Ïîíàñòàâèòü Thread.yield() èëè Thread.sleep(1) â
ðàçíûõ ìåñòàõ êîäà
Èñïîëüçîâàòü ≈ 2 ∗ NCPU íèòåé
×òîáû è âñå g€… áûëè çàíÿòûD à íèòè è âûòåñíÿëèñüD è íå
ïðîñòàèâàëè ñëèøêîì äîëãî
194. ×òî äåëàòü ñ ïðîèçîøåäøèìè îøèáêàìè
Ãëàâíîå íå äàòü èì óñêîëüçíóòü.
Íå äàâàòü
”
îãíåîïàñíûå“ âû÷èñëåíèÿ âíåøíèì API îíè
÷àñòî ãëîòàþò èñêëþ÷åíèÿ. Îáåðòûâàòü ëîããèíãîì.
ixe™utorƒervi™e
Îáðàáîò÷èêè ñîáûòèé â q‡„
ÏîëàãàþD îíè íå îäèíîêèF
Ïî âîçìîæíîñòè íå òåðÿòü èíôîðìàöèþ î ïîòîêå
èñïîëíåíèÿ
195. ×òî äåëàòü ñ ïðîèçîøåäøèìè îøèáêàìè
Ãëàâíîå íå äàòü èì óñêîëüçíóòü.
Íå äàâàòü
”
îãíåîïàñíûå“ âû÷èñëåíèÿ âíåøíèì API îíè
÷àñòî ãëîòàþò èñêëþ÷åíèÿ. Îáåðòûâàòü ëîããèíãîì.
Ïî âîçìîæíîñòè íå òåðÿòü èíôîðìàöèþ î ïîòîêå
èñïîëíåíèÿ
Ïðè àñèíõðîííîì âûçîâå çàïîìíèòü ñòåêòðåéñ èíèöèàòîðàX
îí ïðèãîäèòñÿ ïðè èñêëþ÷åíèè â ðåàêòîðåF
Àðòèëëåðèÿ äëÿ îòëàäêè äåäëîêîâX áëîêèðóåìûé ðåñóðñ
õðàíèò ñòåêòðåéñ çàõâàòàF
Ïðîâåðåíî â áîåâûõ óñëîâèÿõ. Áåçóìíûå èçäåðæêè, íî
ðåäêèé áàã óñòîèò.
196. Òóëû
TestNG èìååò íåáîëüøèå ñïåöèàëüíûå ñðåäñòâà
@Test(threadPoolSize=5,invocationCount=10,threadMap=2,2,2,3,1)
MultithreadedTC
(http://code.google.com/p/multithreadedtc/A
assertTick(n), waitForTick(n)
Ïîíàñòàâèòü òèêîâ ìîæíî òîëüêî â òåñòîâîì êîäå
Óïîìÿíóòûé tEvyD tr—™e™he™k F F F