如何排队我的Python锁?

Swi*_*ore 12 python multithreading synchronization locking

有没有办法让python锁排队?到目前为止,我一直在我的代码中假设threading.lock在队列上运行.看起来它只是锁定一个随机的锁定器.这对我不好,因为我正在工作的程序(游戏)高度依赖于以正确的顺序获取消息.python中是否有排队的锁?如果是这样,我会在处理时间上损失多少?

Tim*_*ers 5

我完全赞同这些评论,声称你可能会以一种无用的方式思考这个问题.锁提供系列化,而不是在所有打算提供订购.执行订单的沼泽标准,简单且可靠的方法是使用aQueue.Queue

CPython将其留给操作系统来决定获取锁定的顺序.在大多数系统中,这似乎或多或少是"随机的".这无法改变.

也就是说,我将展示一种实现"FIFO锁定"的方法.这既不难也不容易 - 介于两者之间 - 你不应该使用它;-)我担心只有你能回答"我在处理时间上会损失多少?" 问题 - 我们不知道您使用锁的程度有多大,或者您的应用程序引发了多少锁竞争.但是,通过研究这段代码,您可以获得粗略的感觉.

import threading, collections

class QLock:
    def __init__(self):
        self.lock = threading.Lock()
        self.waiters = collections.deque()
        self.count = 0

    def acquire(self):
        self.lock.acquire()
        if self.count:
            new_lock = threading.Lock()
            new_lock.acquire()
            self.waiters.append(new_lock)
            self.lock.release()
            new_lock.acquire()
            self.lock.acquire()
        self.count += 1
        self.lock.release()

    def release(self):
        with self.lock:
            if not self.count:
                raise ValueError("lock not acquired")
            self.count -= 1
            if self.waiters:
                self.waiters.popleft().release()

    def locked(self):
        return self.count > 0
Run Code Online (Sandbox Code Playgroud)

这是一个小小的测试驱动程序,可以用显而易见的方式更改它QLock或者threading.Lock:

def work(name):
    qlock.acquire()
    acqorder.append(name)

from time import sleep
if 0:
    qlock = threading.Lock()
else:
    qlock = QLock()
qlock.acquire()
acqorder = []
ts = []
for name in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
    t = threading.Thread(target=work, args=(name,))
    t.start()
    ts.append(t)
    sleep(0.1) # probably enough time for .acquire() to run
for t in ts:
    while not qlock.locked():
        sleep(0)  # yield time slice
    qlock.release()
for t in ts:
    t.join()
assert qlock.locked()
qlock.release()
assert not qlock.locked()
print "".join(acqorder)
Run Code Online (Sandbox Code Playgroud)

刚刚在我的盒子上,使用3次运行threading.Lock产生了这个输出:

BACDEFGHIJKLMNOPQRSTUVWXYZ
ABCDEFGHIJKLMNOPQRSUVWXYZT
ABCEDFGHIJKLMNOPQRSTUVWXYZ
Run Code Online (Sandbox Code Playgroud)

所以它当然不是随机的,但它也不是完全可预测的.用它QLock来运行它,输出应始终是:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
Run Code Online (Sandbox Code Playgroud)