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

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: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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

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: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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

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: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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...
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

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

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
Antworten