【问题标题】:Proper use of mutexes in Python在 Python 中正确使用互斥锁
【发布时间】:2010-07-22 14:40:15
【问题描述】:

我从 python 中的多线程开始(或者至少我的脚本有可能创建多个线程)。这个算法是互斥锁的正确用法吗?我还没有测试过这段代码,它可能甚至无法工作。我只希望 processData 在一个线程中运行(一次一个)并且主 while 循环继续运行,即使队列中有一个线程。

from threading import Thread
from win32event import CreateMutex
mutex = CreateMutex(None, False, "My Crazy Mutex")
while(1)
    t = Thread(target=self.processData, args=(some_data,))
    t.start()
    mutex.lock()

def processData(self, data)
    while(1)
        if mutex.test() == False:
            do some stuff
            break

编辑:重新阅读我的代码,我发现它大错特错。但是,嘿,这就是我在这里寻求帮助的原因。

【问题讨论】:

  • 很难弄清楚你想做什么。您需要更详细地解释您的意图。
  • @Marcelo Cantos,对不起,你可能是对的。我希望我在 processData 中的代码以新的方式开始。我只希望一个线程能够一次处理数据,并且按照发送数据的顺序来处理数据。我还希望主 while 循环在其他线程在队列中时继续循环。
  • @Richard:如果您打算序列化所有处理,为什么还要使用线程?一个简单的循环有什么问题?另外,为什么要让主线程继续循环?它只会消耗 CPU,可能会饿死其他线程。
  • @Marcelo Cantos,这不是我的实际程序。我的实际脚本已达到 500 多行代码,其中包括数据库条目和电子邮件。我希望主线程只读取一个串行端口,以便在处理接收到的数据之前填充缓冲区的可能性较小。如果我错了,请纠正我,但我认为这正是使用线程或多处理的地方
  • @Richard:这对主线程来说是有意义的,但是如果所有其他处理都将是顺序的,那么您可以只创建一个其他线程来完成所有其他工作。

标签: python multithreading mutex


【解决方案1】:

我不知道您为什么使用 Window 的 Mutex 而不是 Python 的。使用 Python 方法,这非常简单:

from threading import Thread, Lock

mutex = Lock()

def processData(data):
    mutex.acquire()
    try:
        print('Do some stuff')
    finally:
        mutex.release()

while True:
    t = Thread(target = processData, args = (some_data,))
    t.start()

但请注意,由于 CPython 的体系结构(即Global Interpreter Lock),您实际上一次只能运行一个线程——如果其中许多线程是 I/O 绑定的,这很好,尽管您'会希望尽可能多地释放锁,这样 I/O 绑定线程就不会阻塞其他线程的运行。

对于 Python 2.6 及更高版本,另一种方法是使用 Python 的 multiprocessing 包。它反映了threading 包,但会创建可以同时运行的全新进程。更新您的示例很简单:

from multiprocessing import Process, Lock

mutex = Lock()

def processData(data):
    with mutex:
        print('Do some stuff')

if __name__ == '__main__':
    while True:
        p = Process(target = processData, args = (some_data,))
        p.start()

【讨论】:

  • 我试过你的代码,我得到了这个错误:with mutex: SyntaxError: invalid syntax。我想我可以使用 try: except: 在我的函数中我使用的是 python 2.4
  • with 是 Python 2.5,multiprocessing 是 Python 2.6。相应地进行了编辑。
  • "如果其中一些是 I/O 绑定的,这很好" 实际上,如果它们是 CPU 绑定的也可以,只要这是在调用用 C 编写的库而不是纯Python 代码(例如,如果您在 numpy 中操作大型矩阵),因为 GIL 在这些调用期间被解锁。
  • @demented 刺猬:mutex 模块已弃用。不推荐使用在答案中完成的使用threadingmultiprocessing 模块创建互斥锁。
  • 非常适合 I/O 尤其是消息对齐
【解决方案2】:

这是我想出的解决方案:

import time
from threading import Thread
from threading import Lock

def myfunc(i, mutex):
    mutex.acquire(1)
    time.sleep(1)
    print "Thread: %d" %i
    mutex.release()


mutex = Lock()
for i in range(0,10):
    t = Thread(target=myfunc, args=(i,mutex))
    t.start()
    print "main loop %d" %i

输出:

main loop 0
main loop 1
main loop 2
main loop 3
main loop 4
main loop 5
main loop 6
main loop 7
main loop 8
main loop 9
Thread: 0
Thread: 1
Thread: 2
Thread: 3
Thread: 4
Thread: 5
Thread: 6
Thread: 7
Thread: 8
Thread: 9

【讨论】:

  • 存在潜在的死锁。如果 print 语句抛出异常,您将永远不会释放互斥锁。您需要使用try/releasewith 来确保释放锁。看我的回答。
  • 另外,不需要将互斥锁作为参数传递给函数。它在全局范围内可用。
【解决方案3】:

我想从chris-b 改进answer 多一点。

下面是我的代码:

from threading import Thread, Lock
import threading
mutex = Lock()


def processData(data, thread_safe):
    if thread_safe:
        mutex.acquire()
    try:
        thread_id = threading.get_ident()
        print('\nProcessing data:', data, "ThreadId:", thread_id)
    finally:
        if thread_safe:
            mutex.release()


counter = 0
max_run = 100
thread_safe = False
while True:
    some_data = counter        
    t = Thread(target=processData, args=(some_data, thread_safe))
    t.start()
    counter = counter + 1
    if counter >= max_run:
        break

在第一次运行时,如果在while循环中设置thread_safe = False,则不会使用互斥锁,线程将在打印方法中相互跳过,如下所示;

但是,如果你设置thread_safe = True 并运行它,你会看到所有的输出都非常好;

希望这会有所帮助。

【讨论】:

  • processData() 的开头复制thread_safe 并在函数中使用该副本。 thread_safe 是一个外部状态变量,在执行过程中可能会发生变化,再次导致不释放互斥锁。
【解决方案4】:

你必须在某个时候解锁你的互斥锁......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-30
    • 1970-01-01
    • 1970-01-01
    • 2021-08-19
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多