Queue equivalent?

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.
Jan.O
User
Beiträge: 61
Registriert: Samstag 26. April 2008, 00:32

Queue equivalent?

Beitragvon Jan.O » Montag 5. Mai 2008, 23:04

Hi,

diese Klasse erfült doch die selben funktionen wie eine Queue und ist genau so thread-save, oder liege ich da falsch? Diese simple Klasse ist nämlich 4 mal so schnell wie die implementierte "Queue".

Code: Alles auswählen

import threading

class myQueue:

   def __init__(self):
      self.lock = threading.Lock();
      self.que = []
      
   def put(self, obj):
      self.lock.acquire()
      self.que.append(obj)
      self.lock.release()
      
   def get(self):
      self.lock.acquire()
      obj = self.que.pop(0)
      self.lock.release()
      
      return obj;
EyDu
User
Beiträge: 4866
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Beitragvon EyDu » Montag 5. Mai 2008, 23:25

Nee, da fehlt ganz entscheidende Funktionalität: So blockiert "Queue" bei einem Aufruf von "get" wenn keine Elemente in der Schlange vorhanden sind, das ist bei dir nicht der Fall.

Außerdem bietet "Queue" noch mehr Funktionalität, wie zum Beispiel Timeouts.

Außerdem fehlt bei dir ein try-finally in der "get"-Methode. Wenn keine Element in der Schlange hängt, dann wird eine Exception geworfen, aber der Lock nicht gelöst. Damit ist die Queue dann hinüber.

Schau dir doch einfach mal den Quellcode vom Original-"Queue" an, liegt irgendwo in deinem Python-Ordner.
Jan.O
User
Beiträge: 61
Registriert: Samstag 26. April 2008, 00:32

Beitragvon Jan.O » Montag 5. Mai 2008, 23:43

Ok, aber jetzt. Es kann keine exception mehr auftreten und wenn die Queue leer ist, wird gewartet.

Edit: Ne, so geht das noch nicht.

Code: Alles auswählen

import threading
class myQueue:
def __init__(self):
  self.lock = threading.Lock();
  self.emptyLock = threading.Lock();
  self.que = []
  self.count = 0
      
  def put(self, obj):
    self.lock.acquire()
    self.que.append(obj)
   
    if self.count == 0:
      self.emptyLock.release()
   
    self.count = self.count + 1
    self.lock.release()
      
   def get(self):
    self.lock.acquire()
    self.emptyLock.acquire()
     
    obj = self.que.pop(0)
    self.count = self.count - 1
   
    if self.count > 0:
      self.emptyLock.release()

    self.lock.release()
      
      return obj;

EyDu
User
Beiträge: 4866
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Beitragvon EyDu » Dienstag 6. Mai 2008, 10:50

Code: Alles auswählen

class myQueue:
    def __init__(self):
        self.lock = threading.Lock()
        self.emptyLock = threading.Lock()
        self.queue = []
   
    def put(self, elem):
        self.lock.acquire()
        self.queue.append(elem)
       
        if len(self.queue) == 1:
            self.emptyLock.release()
       
        self.lock.release()
   
    def pop(self):
        try:
            self.lock.acquire()
            self.lock.emptyLock()
       
            return self.queue.pop(0)
        finally:
            if len(self.queue) == 0:
                self.emptyLock.acquire()
       
            self.lock.release()


Ist ungetestet, aber Timeouts fehlen zum Beispiel immer noch.
Benutzeravatar
Masaru
User
Beiträge: 425
Registriert: Mittwoch 4. August 2004, 22:17

Beitragvon Masaru » Dienstag 6. Mai 2008, 11:15

Ohha :shock:

NIE ein "acquire" mit folgendem Code, ohne diesen in einem try-finally-Block unterzubringen, wobei das "release" im finally-Teil abgehandelt wird.

Ihr werdet echt unglücklich, wenn Ihr mit mehrere Threads arbeitet, und einer mal sich abschiesst. Das herauszufinden ist nicht gerade lustig ;).

Bsp.-Konstrukt:

Code: Alles auswählen

import threading

class Sample(object):
    def __init__(self):
        self.__lock = threading.Lock()

    def get(self):
        self.__lock.acquire()
        try:
            # hier die Anwendungslogic
        finally:
            self.__lock.release()

>>Masaru<<
EyDu
User
Beiträge: 4866
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Beitragvon EyDu » Dienstag 6. Mai 2008, 11:24

Das ist doch nur ein Beispiel, ich war lediglich zu faul, das Ergebnis zwischenzuspeichern. Jetzt weiss ich aber, warum "from Tkinter import *" so verbreitet ist...
Benutzeravatar
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Beitragvon mitsuhiko » Dienstag 6. Mai 2008, 11:35

Die Queue vom ersten Beispiel hat keinen Vorteil gegenüber list. :wink: Wenn man sowas will nimmt man collections.deque. (Double-ended queue)
TUFKAB – the user formerly known as blackbird
Mad-Marty
User
Beiträge: 317
Registriert: Mittwoch 18. Januar 2006, 19:46

Beitragvon Mad-Marty » Dienstag 6. Mai 2008, 22:38

Glaubs ruhig die Queue.Queue ist wirklich gut.

Das was mir u.a. fehlte war die möglichkeit das 1. element zu inspizieren ohne es herauszunehmen und persistent syncs bei jeder änderung auf die HDD.


Am besten du versuchst nicht eine eigene Queue zu bauen wenn nicht nötig,
gerade wenn es mit echten threads arbeitet und nicht nur 1 lock beachtet werden muss, musst du extrem viele möglichkeiten durchdenken (was wenn ... X ... in Y eine Exception hat ... etc).

Außer du hast Zeit ... dann kann das mal ganz nett sein :P

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot]