0

Ich habe mit zwei Python-Warteschlangen zu tun.
Kurzbeschreibung meiner Frage:
Kunden gehen durch die waiting queue (q1) und sie (die Kunden) werden danach serviert.
Die Größe der waiting queue kann nicht größer als N sein (10 in meinem Programm).
Wenn waiting queue voll wird, werden die Clients an outside queue (q2, Größe 20) übergeben. Wenn die externe Warteschlange voll wird, werden Clients abgelehnt und nicht bedient.
Jeder Client, der eine Warteschlange verlassen hat, ermöglicht es einem anderen Client von außerhalb der Warteschlange, der Warteschlange beizutreten.Kann Artikel von einer Warteschlange zu einer anderen nicht ausrichten

Arbeiten mit Warteschlangen sollten Thread-sicher sein.

Im Folgenden implementiert ich ungefähr, was ich will. Aber ich bin mit dem Problem konfrontiert - einen Client von außerhalb der Warteschlange (q1) in die Warteschlange (q2) während der Ausführung in die Warteschlange serve Funktion einreihen. Ich glaube, ich habe etwas Wichtiges verloren oder vergessen. Ich denke, diese Aussage q1.put(client) blockiert dauerhaft, weiß aber nicht warum.

import time 
import threading 
from random import randrange 
from Queue import Queue, Full as FullQueue 


class Client(object): 
    def __repr__(self): 
     return '<{0}: {1}>'.format(self.__class__.__name__, id(self)) 


def serve(q1, q2): 
    while True: 
     if not q2.empty(): 
      client = q2.get() 
      print '%s leaved outside queue' % client 
      q1.put(client) 
      print '%s is in the waiting queue' % client 
      q2.task_done() 

     client = q1.get() 
     print '%s leaved waiting queue for serving' % client 
     time.sleep(2) # Do something with client 
     q1.task_done() 


def main(): 
    waiting_queue = Queue(10) 
    outside_queue = Queue(20) 

    for _ in range(2): 
     worker = threading.Thread(target=serve, args=(waiting_queue, outside_queue)) 
     worker.setDaemon(True) 
     worker.start() 

    delays = [randrange(1, 5) for _ in range(100)] 

    # Every d seconds 10 clients enter to the waiting queue 
    for d in delays: 
     time.sleep(d) 
     for _ in range(10): 
      client = Client() 
      try: 
       waiting_queue.put_nowait(client) 
      except FullQueue: 
       print 'Waiting queue is full. Please line up in outside queue.' 
       try: 
        outside_queue.put_nowait(client) 
       except FullQueue: 
        print 'Outside queue is full. Please go out.' 

    waiting_queue.join() 
    outside_queue.join() 
    print 'Done' 

Antwort

0

Endlich fand ich die Lösung. Ich überprüfe docs aufmerksame If full() returns True it doesn’t guarantee that a subsequent call to get() will not blockhttps://docs.python.org/2/library/queue.html#Queue.Queue.full

, deshalb, q1.full() in einigen Threads nicht zuverlässig ist. Ich habe Mutex vor Punkt zu Warteschlangen Einfügen und Warteschlange Überprüfung ist voll:

class Client(object): 
    def __init__(self, ident): 
     self.ident = ident 

    def __repr__(self): 
     return '<{0}: {1}>'.format(self.__class__.__name__, self.ident) 


def serve(q1, q2, mutex): 
    while True: 
     client = q1.get() 
     print '%s leaved waiting queue for serving' % client 
     time.sleep(2) # Do something with client 
     q1.task_done() 

     with mutex: 
      if not q2.empty() and not q1.full(): 
       client = q2.get() 
       print '%s leaved outside queue' % client 
       q1.put(client) 
       print '%s is in the waiting queue' % client 
       q2.task_done() 


def main(): 
    waiting_queue = Queue(10) 
    outside_queue = Queue(20) 

    lock = threading.RLock() 

    for _ in range(2): 
     worker = threading.Thread(target=serve, args=(waiting_queue, outside_queue, lock)) 
     worker.setDaemon(True) 
     worker.start() 

    # Every 1-5 seconds 10 clients enter to the waiting room 
    i = 1 # Used for unique <int> client's id 
    while True: 
     delay = randrange(1, 5) 
     time.sleep(delay) 
     for _ in range(10): 
      client = Client(i) 
      try: 
       lock.acquire() 
       if not waiting_queue.full(): 
        waiting_queue.put(client) 
       else: 
        outside_queue.put_nowait(client) 
      except FullQueue: 
       # print 'Outside queue is full. Please go out.' 
       pass 
      finally: 
       lock.release() 

      i += 1 

    waiting_queue.join() 
    outside_queue.join() 
    print 'Done' 

Jetzt ist es gut funktioniert.

Verwandte Themen