Python 多线程资源访问-锁放在哪里?

Python 多线程资源访问-锁放在哪里?,python,multithreading,locking,Python,Multithreading,Locking,我有线程代码,每个线程都需要写入同一个文件。为了防止并发问题,我使用了锁对象 我的问题是我是否正确使用了锁。如果我在每个线程内设置锁,那么该锁是全局的还是仅特定于该特定线程 基本上,我应该首先创建一个锁并将其引用传递给每个线程,还是像我在这里所做的那样从线程内部设置它 import time from threading import Thread, Lock def main(): for i in range(20): agent = Agent(i)

我有线程代码,每个线程都需要写入同一个文件。为了防止并发问题,我使用了锁对象

我的问题是我是否正确使用了锁。如果我在每个线程内设置锁,那么该锁是全局的还是仅特定于该特定线程

基本上,我应该首先创建一个锁并将其引用传递给每个线程,还是像我在这里所做的那样从线程内部设置它

import time
from threading import Thread, Lock

def main():
    for i in range(20):
        agent = Agent(i)
        agent.start()

class Agent(Thread):
    def __init__(self, thread_num):
        Thread.__init__(self)
        self.thread_num = thread_num

    def run(self):
        while True:
            print 'hello from thread %s' % self.thread_num
            self.write_result()   

    def write_result(self):
        lock = Lock()
        lock.acquire()
        try:
            f = open('foo.txt', 'a')
            f.write('hello from thread %s\n' % self.thread_num)
            f.flush()
            f.close()
        finally:
            lock.release()

if __name__ == '__main__':
    main()

在方法外部创建锁

class Agent(Thread):
    mylock = Lock()
    def write_result(self):
        self.mylock.acquire()
        try:
            ...
        finally:
            self.mylock.release()
或者如果使用python>=2.5:

class Agent(Thread):
    mylock = Lock()
    def write_result(self):
        with self.mylock:
            ...
要在python 2.5中使用该语句,必须从将来导入该语句:

from __future__ import with_statement

lock()方法为每个调用返回一个lock对象。因此,每个线程(实际上每次调用write_result)都将有一个不同的锁对象。而且不会有锁

所使用的锁必须是所有线程共用的,或者至少确保两个锁不能同时锁定同一资源。

我非常确定每个线程的锁必须是相同的对象。试试这个:

import time
from threading import Thread, Lock

def main():
    lock = Lock()
    for i in range(20):
        agent = Agent(i, lock)
        agent.start()

class Agent(Thread, Lock):
    def __init__(self, thread_num, lock):
        Thread.__init__(self)
        self.thread_num = thread_num
        self.lock = lock

    def run(self):
        while True:
            print 'hello from thread %s' % self.thread_num
            self.write_result()   

    def write_result(self):
        self.lock.acquire()
        try:
            f = open('foo.txt', 'a')
            f.write('hello from thread %s\n' % self.thread_num)
            f.flush()
            f.close()
        finally:
            lock.release()

if __name__ == '__main__':
    main()

锁实例应与文件实例相关联


换句话说,您应该同时创建锁和文件,并将它们传递给每个线程。

对于您的用例,一种方法可以是编写一个锁的
文件
子类:

class LockedWrite(file):
    """ Wrapper class to a file object that locks writes """
    def __init__(self, *args, **kwds):
        super(LockedWrite, self).__init__(*args, **kwds)
        self._lock = Lock()

    def write(self, *args, **kwds):
        self._lock.acquire()
        try:
            super(LockedWrite, self).write(*args, **kwds)
        finally:
            self._lock.release()
要在代码中使用,只需替换以下函数:

def main():
    f = LockedWrite('foo.txt', 'a')

    for i in range(20):
        agent = Agent(i, f)
        agent.start()

class Agent(Thread):
    def __init__(self, thread_num, fileobj):
        Thread.__init__(self)
        self.thread_num = thread_num
        self._file = fileobj    

#   ...

    def write_result(self):
        self._file.write('hello from thread %s\n' % self.thread_num)

这种方法将文件锁定放在文件本身,看起来更干净。通过指定一个线程(可能是专门为此目的创建的)作为写入文件的唯一线程,您可以简化一些事情(以稍微增加开销为代价),并通过将要添加到文件中的字符串放入
queue.queue
对象,让所有其他线程委托给文件编写器


队列具有所有内置的锁定功能,因此任何线程都可以随时安全地调用
Queue.put()
。文件编写器将是唯一调用
Queue.get()
的线程,并且可能会花费大量时间阻止该调用(有一个合理的超时,以允许线程干净地响应关闭请求)。所有的同步问题都将由队列处理,您不必担心是否忘记了某个地方的锁获取/释放…:)

nosklo。为什么这样不行?锁首先被创建,然后被传递到每个线程中。对不起,我忘记了将锁对象传递给代理构造函数。更正。是的,您已将其移到方法之外,但仍在线程本身中创建它。这不是一个问题吗?@cgoldberd:它被创建为一个类属性,这意味着将为所有线程创建一个类属性。这是一个更好的保存它的地方,因为所有内容都保留在thread类上。明白了。除了毫无意义的“filelock=Lock()”部分之外,我更喜欢这个解决方案。如果它以某种方式拦截了打开foo.txt进行写入/追加的其他尝试,并返回到原始的LockedWrite对象,那就更好了。我只是需要一些关于锁的说明。