hazelcast / hazelcast/hazelcast-python-client

Extreme slow down when using Map#lock/unlock from multiple threads [API-1968]

Offen
#616 3 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Python 3 to-jira Type: Defect
Vorherrschende Sprache
Python
Sterne
116
Forks
78
Ø Merge
10 T. 22 Std.
Gemergte PRs (30 T.)
1

Beschreibung

Running the [Pessimistic Locking](https://docs.hazelcast.com/hazelcast/5.2/data-structures/locking-maps#pessimistic-locking) example from multiple threads using the same client takes vastly different amounts of time.

The sequential runs of the same code can give:
```
It took 68.364421721 second(s) to finish.
It took 2666.208992902 second(s) to finish.
```
Using one Hazelcast instance. The behaviour is reproducible on MacOS and Linux. Using python3

The code sample:

```
import hazelcast
from time import perf_counter
from concurrent.futures import ThreadPoolExecutor
from threading import Thread

if __name__ == "__main__":
client = hazelcast.client.HazelcastClient(
cluster_name="dev",
lifecycle_listeners=[
lambda state: print("Lifecycle event >>>", state),
]
)

# Defining send_query func and pooled_query func, to send requests using ThreadPoolExecutor
desired_range = range(10000)
desired_threads = 10

# Create a Distributed Map in the cluster
counter_map = client.get_map("counter-map").blocking()

counter_map.put("key", 0)

# Pesimistic Locking
def send_query(range_parameter):
for i in range_parameter:
counter_map.lock("key")
try:
counter = counter_map.get("key") + 1
counter_map.put("key", counter)
finally:
counter_map.unlock("key")

def pooled_query():
# create the thread pool
n_threads = desired_threads
with ThreadPoolExecutor(n_threads) as executor:
# push query for each thread
_ = [executor.submit(send_query, desired_range) for i in range(0, desired_threads)]

def pooled_query_thread():
threads = []
for i in range(desired_threads):
thread = Thread(target=send_query, args=(desired_range,))
threads.append(thread)

for thr in threads:
thr.start()

for thr in threads:
thr.join()

## Timer start
start = perf_counter()

## Invoke ThreadPoolExecutor to send requests
if __name__ == "__main__":
# pooled_query()
pooled_query_thread()

## Timer end
finish = perf_counter()

print(f'It took {finish-start} second(s) to finish.')

for key, value in counter_map.entry_set():
print(key, value)

client.shutdown()
```

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Beginne damit, den bereitgestellten Python-Reproducer mit einem Hazelcast-Client, mehreren Threads und Map#lock/unlock auszuführen, und untersuche anschließend die vom blockierenden Map-Lock sowie von den Operationen lock, get, put und unlock verwendeten Client-Pfade. Erledigt ist die Aufgabe, wenn identifiziert wurde, warum die nebenläufige Ausführung drastisch langsamer als die sequenzielle Ausführung ist, und verifiziert wurde, dass die gemeldete Arbeitslast die Verlangsamung nicht mehr zeigt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
distributed-systems
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
38/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.