Einen Zähler threadsicher inkrementieren und zurückgeben

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
Michael Schneider
User
Beiträge: 567
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Einen Zähler threadsicher inkrementieren und zurückgeben

Beitragvon Michael Schneider » Sonntag 1. Juli 2007, 11:15

Hallo,

ich habe mal wieder eine recht allgemeine Frage, die ich für verschiedene Skripte/Programme benötige.

Es kommt hin und wieder vor, dass ich eine neue Instanz einer laufenden Nummer benötige. Ohne Threads geht das folgendermaßen problemlos:

Code: Alles auswählen

class Lnr:
    iLaufendeNummer = 0
    def next(self):
        iNextId = Lnr.iLaufendeNummer
        Lnr.iLaufendeNummer += 1
        return iNextId

iNext = Lnr.next()

Sobald aber mehrere Threads ins Spiel kommen, besteht die Gefahr, dass der bearbeitete Prozess zwischen Nummerholen und Nummerinkrementieren wechselt und die Nummer zwei mal geholt wird.
Ideal wäre es, wenn eine Funktion wie "i+=1" i um ein erhöhen und gleichzeitig den neuen Wert zurückgeben würde. Ansonsten fällt mir nur ein, dass man einen lock verwendet. Was passiert eigentlich, wenn mehrere Threads gleichzeitig auf dieselbe! Funktion zugreifen?

Ist mein Problem ein Standardfall der Informatik?

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Re: Einen Zähler threadsicher inkrementieren und zurückgeben

Beitragvon gerold » Sonntag 1. Juli 2007, 11:32

Michael Schneider hat geschrieben:laufenden Nummer

Hallo Michael!

Wegen dem Zähler. Den brauchst du nicht mehr extra implementieren. Den gibt es schon:

Code: Alles auswählen

>>> import itertools
>>> counter = itertools.count()
>>> counter.next()
0
>>> counter.next()
1
>>> counter.next()
2
>>>

Ob das Ganze auch threadsafe ist, weiß ich noch nicht. Mal sehen ob ich etwas aus den Quellen raus lesen kann.

EDIT:

Ich konnte im Quellcode keinen Hinweis auf einen Lock entdecken. Allerdings weiß ich nicht, wo die Grenzen beim Threading in Python sind und ob da intern nicht von GIL eine Grenze gezogen wird. Hier ist eine Aussage eines Fachmannes gefragt.

Bis es so weit ist -- hier ein Vorschlag:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import itertools
import threading


class Counter(object):
   
    def __init__(self):
        self._count = itertools.count()
        self._lock = threading.Lock()
   
   
    def next(self):
        self._lock.acquire()
        try:
            return self._count.next()
        finally:
            self._lock.release()


def main():
    counter = Counter()
    print counter.next()
    print counter.next()
    print counter.next()


if __name__ == "__main__":
    main()

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
lunar

Beitragvon lunar » Sonntag 1. Juli 2007, 11:56

Aus der itertools-Dokumentation:
New in version 2.3.


Da bleibt Michael Schneider leider außen vor ;) Hätte allerdings imho auch nichts geholfen, da die Implementierung für mich mit meinen beschränkten C-Kenntnissen nicht thread-sicher aussieht.

Ich würde ein einfach Lock verwenden, um den Zugriff auf den Counter abzusichern, so dieser über verschiedene Threads verwendet wird.

Edit: Zu langsam. Während ich noch tippe, hat gerold mal wieder ein komplettes Snippet auf die Beine gestellt ;)
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Beitragvon birkenfeld » Sonntag 1. Juli 2007, 14:25

Nachdem ja immer nur ein Thread überhaupt gleichzeitig Python-Code ausführen kann, und in der Implementierung von count() kein Py_BEGIN_ALLOW_THREADS vorkommt, halte ich das durchaus für threadsicher.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
lunar

Beitragvon lunar » Sonntag 1. Juli 2007, 14:34

birkenfeld hat geschrieben:Nachdem ja immer nur ein Thread überhaupt gleichzeitig Python-Code ausführen kann, und in der Implementierung von count() kein Py_BEGIN_ALLOW_THREADS vorkommt, halte ich das durchaus für threadsicher.

Wieder was gelehrt.
BlackJack

Beitragvon BlackJack » Sonntag 1. Juli 2007, 17:41

Gilt natürlich nur solange man CPython benutzt und es dort das GIL gibt.

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot]