0

私は2つのpythonキューを扱います。
短い説明:
クライアントはwaiting queue(q1)を通過し、その後(クライアント)が配信されます。
waiting queueのサイズはN(プログラムでは10)を超えることはできません。
waiting queueがいっぱいになると、クライアントはoutside queue(q2、サイズ20)になります。外部キューがいっぱいになると、クライアントは拒否され、配信されません。
待機キューを残したすべてのクライアントは、外部キューからの別のクライアントが待機キューに参加できるようにします。あるキューから別のキューにアイテムを並べ替えることができません

キューの操作はスレッドセーフである必要があります。

以下、私が望むものをほぼ実装しました。しかし、私はこの問題に直面しています - 実行中に外部キュー(q1)から待機キュー(q2)にクライアントをエンキューします。serve機能。私は何か重要なことを忘れてしまったと思います。私はこの文q1.put(client)は永久にブロックすると思うが、理由を知らない。

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' 

答えて

0

最後に解決策が見つかりました。私はq1.full()は、いくつかのスレッドで信頼できるものではありません理由です 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

より丁寧なドキュメントを確認してください。キューに項目を挿入する前にmutexを追加し、キューがいっぱいであることを確認しました。

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' 

これでうまくいきました。

関連する問題