Discussion:
Parallelprogrammierung
(zu alt für eine Antwort)
Christian H. Kuhn
2017-09-23 14:44:27 UTC
Permalink
Hallo Gemeinde,

So langsam wird das was. Umfangreiches Refactoring dank der vielen Tips
hier: single responsibility, dependency injection deutlich besser,
umgesetzt. Tests verbessert dank Mockito, jimfs, von PowerMock nur
Whitebox. So langsam wird der Code vorzeigbar ;-)

Ein Problem habe ich noch.

public class QFdsbDatabase {

[...]

void importData([...]) {
[...]
}

public List<String[]>) exportData(String, String) {
[...]
}
}

exportData() und importData() schließen sich gegenseitig aus. Das bekäme
ich mit synchronized hin. Aber.

Es sollen mehrere Threads exportData() aufrufen können, ohne aufeinander
warten zu müssen.

importData() soll auf die Beendigung vom letzten exportData() warten.

exportData() soll nicht auf die Beendigung von importData() warten,
sondern eine Exception werfen. Die Wartezeit kann über eine Stunde
betragen, da scheint mir ein Abbruch besser.

Sobald importData() wartet, soll jeder exportData()-Aufruf eine
Exception werfen, nicht erst, sobald importData() rechnet.

Alles, was ich an Literatur zur Parallelprogrammierung gefunden habe,
geht davon aus, dass immer nur ein Thread im kritischen Bereich sein
darf. Dass wie hier bei exportData() mehrere Threads gleichzeitig laufen
dürfen und diese n Threads auf der einen Seite einem Thread
gegenüberstehen, habe ich nirgendwo gefunden. Auch habe ich nur
Literatur gefunden, in der ein blockierter Thread wartet und nicht via
Exception geregelt wird.

Dennoch scheint mir mein Problem nicht so abwegig, dass es nicht schon
irgendwo gelöst wurde. Und wenn ich keine Lösung finde, suche ich
falsch. Kann mich jemand auf das richtige Gleis heben?

TIA
QNo
Marcel Mueller
2017-09-24 08:30:06 UTC
Permalink
Post by Christian H. Kuhn
Ein Problem habe ich noch.
[...]
Post by Christian H. Kuhn
exportData() und importData() schließen sich gegenseitig aus. Das bekäme
ich mit synchronized hin. Aber.
Es sollen mehrere Threads exportData() aufrufen können, ohne aufeinander
warten zu müssen.
Dur suchst ein ->ReadWriteLock.
Post by Christian H. Kuhn
importData() soll auf die Beendigung vom letzten exportData() warten.
exportData() soll nicht auf die Beendigung von importData() warten,
sondern eine Exception werfen. Die Wartezeit kann über eine Stunde
betragen, da scheint mir ein Abbruch besser.
Sobald importData() wartet, soll jeder exportData()-Aufruf eine
Exception werfen, nicht erst, sobald importData() rechnet.
Einfach beim Warten tryLock() nehmen.
Post by Christian H. Kuhn
Alles, was ich an Literatur zur Parallelprogrammierung gefunden habe,
geht davon aus, dass immer nur ein Thread im kritischen Bereich sein
darf.
Dann hast Du zu wenig gesehen. ;-)
Post by Christian H. Kuhn
Auch habe ich nur
Literatur gefunden, in der ein blockierter Thread wartet und nicht via
Exception geregelt wird.
Das kannst Du selber realisieren, indem Du tryLock() verwendest.
Bibliotheken sollten niemals Exceptions in Standardsituationen werfen.
Dafür sind sie zu teuer. Und daran halten sich die Standard
Lock-Implementierungen auch.
Post by Christian H. Kuhn
Dennoch scheint mir mein Problem nicht so abwegig, dass es nicht schon
irgendwo gelöst wurde. Und wenn ich keine Lösung finde, suche ich
falsch. Kann mich jemand auf das richtige Gleis heben?
Die implementierenden Klasse in Java heißt ReentrantReadWriteLock.


Marcel
Christian H. Kuhn
2017-10-03 13:40:32 UTC
Permalink
Post by Marcel Mueller
Post by Christian H. Kuhn
exportData() und importData() schließen sich gegenseitig aus. Das bekäme
ich mit synchronized hin. Aber.
Es sollen mehrere Threads exportData() aufrufen können, ohne aufeinander
warten zu müssen.
Dur suchst ein ->ReadWriteLock.
In der Tat. Vielen Dank! ReentrantReadWriteLock; importData() macht
einen writeLock().lock(), exportData() einen readLock().tryLock(). Das,
was danach kommt, steht sowieso in einem try-with-resources-Block, da
ist das finally mit dem jeweiligen unlock() kein Problem.
Post by Marcel Mueller
Post by Christian H. Kuhn
Alles, was ich an Literatur zur Parallelprogrammierung gefunden habe,
geht davon aus, dass immer nur ein Thread im kritischen Bereich sein
darf.
Dann hast Du zu wenig gesehen. ;-)
Da sind wir uns einig :-)
Post by Marcel Mueller
Bibliotheken sollten niemals Exceptions in Standardsituationen werfen.
Dafür sind sie zu teuer. Und daran halten sich die Standard
Lock-Implementierungen auch.
Wenn List<String[]> exportData(String, String) den Lock nicht bekommt,
gibt es null zurück. Wer fremde Bibliotheken aufruft und nicht auf null
checkt, hat es nicht besser verdient ;-)

Und nachdem das geklärt ist, ist mir aufgefallen, dass auch andere
Rechner ihre (eingeschränkten) QDatabase-Objekte mit ihren spezifischen
Clients auf die Datenbank zugreifen und nicht über den Prozess, in dem
mein QDatabase-Objekt die Locks verwaltet. Ich darf also noch Locks auf
die Tabellen in Postgresql setzen. Andere Gruppe.

lg
QNo
Patrick Roemer
2017-10-03 18:15:57 UTC
Permalink
Post by Christian H. Kuhn
Post by Marcel Mueller
Bibliotheken sollten niemals Exceptions in Standardsituationen werfen.
Dafür sind sie zu teuer. Und daran halten sich die Standard
Lock-Implementierungen auch.
Wenn List<String[]> exportData(String, String) den Lock nicht bekommt,
gibt es null zurück. Wer fremde Bibliotheken aufruft und nicht auf null
checkt, hat es nicht besser verdient ;-)
Für ein Lock ist es eine Standardsituation, wenn ein acquire nicht auf
Anhieb erfolgreich ist. Für den Benutzer ist es eine Ausnahmesituation,
wenn der Batch-Export nicht durchgeht.
Post by Christian H. Kuhn
Und nachdem das geklärt ist, ist mir aufgefallen, dass auch andere
Rechner ihre (eingeschränkten) QDatabase-Objekte mit ihren spezifischen
Clients auf die Datenbank zugreifen und nicht über den Prozess, in dem
mein QDatabase-Objekt die Locks verwaltet. Ich darf also noch Locks auf
die Tabellen in Postgresql setzen. Andere Gruppe.
Wenn die DB das Transaktionshandling übernimmt, greift das auch für
konkurrente lokale Clients und Du kannst das Lock-Zeugs getrost wieder
zappen.

Viele Grüße,
Patrick
Marcel Mueller
2017-10-08 20:15:27 UTC
Permalink
Post by Patrick Roemer
Post by Christian H. Kuhn
Und nachdem das geklärt ist, ist mir aufgefallen, dass auch andere
Rechner ihre (eingeschränkten) QDatabase-Objekte mit ihren spezifischen
Clients auf die Datenbank zugreifen und nicht über den Prozess, in dem
mein QDatabase-Objekt die Locks verwaltet. Ich darf also noch Locks auf
die Tabellen in Postgresql setzen. Andere Gruppe.
Wenn die DB das Transaktionshandling übernimmt, greift das auch für
konkurrente lokale Clients und Du kannst das Lock-Zeugs getrost wieder
zappen.
Da musst Du aber höllisch aufpassen. Vom Distributed Deadlock bis zur
Snapshot too old Exception ist da so ziemlich alles möglich.

Wirklich sicher wäre man nur im DB-Isolationslevel "Serializable", was
erstens bei weitem nicht jede Datenbank kann und zweitens dem
DB-Administrator auf die Palme bringt, weil es den Durchsatz auf 386-er
Niveau begrenzt.

Es gibt also durchaus gute Gründe sich mit eigenen Sperrkonzepten bei
verteilten Anwendungen zu befassen.


Marcel
Patrick Roemer
2017-10-09 10:36:27 UTC
Permalink
Post by Marcel Mueller
Post by Patrick Roemer
Post by Christian H. Kuhn
Und nachdem das geklärt ist, ist mir aufgefallen, dass auch andere
Rechner ihre (eingeschränkten) QDatabase-Objekte mit ihren spezifischen
Clients auf die Datenbank zugreifen und nicht über den Prozess, in dem
mein QDatabase-Objekt die Locks verwaltet. Ich darf also noch Locks auf
die Tabellen in Postgresql setzen. Andere Gruppe.
Wenn die DB das Transaktionshandling übernimmt, greift das auch für
konkurrente lokale Clients und Du kannst das Lock-Zeugs getrost wieder
zappen.
Da musst Du aber höllisch aufpassen. Vom Distributed Deadlock bis zur
Snapshot too old Exception ist da so ziemlich alles möglich.
Da helfen ihm die VM-lokalen Locking-Konstrukte, die er bisher auf dem
Client eingebaut hat, auch nicht.

Viele Grüße,
Patrick
Christian H. Kuhn
2017-10-12 18:23:57 UTC
Permalink
Post by Marcel Mueller
Da musst Du aber höllisch aufpassen. Vom Distributed Deadlock bis zur
Snapshot too old Exception ist da so ziemlich alles möglich.
Im Allgemeinen hast du sicher recht. Im konkreten Fall gibt es genau
einen Prozess, der Daten ändern darf, und das tut er einmal am Tag. Dazu
gibt es n Clients, die die Daten lesen. Eventuell auch Clients, die ich
nicht kenne. Das dürfen alle gleichzeitig, außer es wird gerade
geschrieben, dann darf niemand lesen. Wenn ich da einen Deadlock haben
will, muss ich schon ziemlich gut (schlecht?) sein.
Post by Marcel Mueller
Wirklich sicher wäre man nur im DB-Isolationslevel "Serializable", was
erstens bei weitem nicht jede Datenbank kann
Postgresql. Kann. LOCK ... IN ACCESS EXCLUSIVE MODE
Post by Marcel Mueller
und zweitens dem
DB-Administrator auf die Palme bringt, weil es den Durchsatz auf 386-er
Niveau begrenzt.
Bei dieser Anwendung: Wayne. cronjob startet täglich morgens, wird bis
mittags fertig, der typische Anwender schläft zu der Zeit ;-) Es ist
nicht auszuschließen, dass das Schreiben der Daten auch einmal pro Woche
reicht.
Post by Marcel Mueller
Es gibt also durchaus gute Gründe sich mit eigenen Sperrkonzepten bei
verteilten Anwendungen zu befassen.
Ja. Hier sollte es allerdings mit explicit locking in der DB reichen.

lg
QNo
Marcel Mueller
2017-10-13 07:01:17 UTC
Permalink
Post by Christian H. Kuhn
Post by Marcel Mueller
Da musst Du aber höllisch aufpassen. Vom Distributed Deadlock bis zur
Snapshot too old Exception ist da so ziemlich alles möglich.
Im Allgemeinen hast du sicher recht. Im konkreten Fall gibt es genau
einen Prozess, der Daten ändern darf, und das tut er einmal am Tag. Dazu
gibt es n Clients, die die Daten lesen. Eventuell auch Clients, die ich
nicht kenne. Das dürfen alle gleichzeitig, außer es wird gerade
geschrieben, dann darf niemand lesen. Wenn ich da einen Deadlock haben
will, muss ich schon ziemlich gut (schlecht?) sein.
Bei MS SQL in der Standardeinstellung reicht das dicke für einen
Deadlock (BTDT).

Bei nur einem "Schreiber" empfiehlt sich Snapshot Isolation alias
Optimistick Locking, wie es bei Oracle Standard ist. Damit kann nur noch
etwas hängen, wenn ein Leser nicht in die Pushen kommt und stundenlang
auf einem Select herumeiert. Dann zerlegt es aber auch nur genau diesen
- also kein Kollateralschaden.
Post by Christian H. Kuhn
Post by Marcel Mueller
Wirklich sicher wäre man nur im DB-Isolationslevel "Serializable", was
erstens bei weitem nicht jede Datenbank kann
Postgresql. Kann. LOCK ... IN ACCESS EXCLUSIVE MODE
Mit Postgres habe ich keine tiefgehenden Erfahrungen. Im Besonderen weiß
ich nicht, ob das Oplocks kann.
Post by Christian H. Kuhn
Bei dieser Anwendung: Wayne. cronjob startet täglich morgens, wird bis
mittags fertig, der typische Anwender schläft zu der Zeit ;-) Es ist
nicht auszuschließen, dass das Schreiben der Daten auch einmal pro Woche
reicht.
Wenn das von morgens bis mittags eine Transaktion ist, könnte selbst das
für Ärger reichen.
Post by Christian H. Kuhn
Post by Marcel Mueller
Es gibt also durchaus gute Gründe sich mit eigenen Sperrkonzepten bei
verteilten Anwendungen zu befassen.
Ja. Hier sollte es allerdings mit explicit locking in der DB reichen.
Sicherlich.

Aber damit ist die Diskussion um die Client-seitigen Locks tatsächlich
irrelevant. Die stiften hier keinen Nutzen.


Marcel

Lesen Sie weiter auf narkive:
Loading...