Python线程锁定与强制计时器延迟

时间:2015-06-11 06:08:33

标签: python multithreading thread-safety

我的理解是,当你在Python中实现全局锁时,这应该为激活锁的线程保留stdout,从而防止其他线程在线程释放锁之前使用stdout。

这不意味着在下面的代码中,线程中的循环" a"应该在线程" b"中的函数之前完成什么输出?当我运行时," 7"那个帖子" c"打印有时会在" a"。

的输出中交错显示

我希望输出始终如下:

 5
 5
 5
 5
 5
 6
 7

但我得到了:

 5
 7
 5
 5
 5
 6

代码:

import threading, time

thelock = threading.Lock()

def afunc(var):
    with thelock:
        for i in range(5):
            time.sleep(.0002)
            print(var)

def bfunc(var):
    print(var)

a=threading.Thread(target=afunc, args=(5,))
b=threading.Thread(target=bfunc, args=(6,))
c=threading.Thread(target=bfunc, args=(7,))
a.start()
b.start()
c.start()

这是OS X 10.10.3中的Python 3.4.3。直接在OS X终端或PyCharm 4.5.1中运行文件时会出现相同的行为。

2 个答案:

答案 0 :(得分:2)

您没有实现全局锁定,因为没有这样的东西。我的意思是,有一个是Global Interpreter Lock,它是语言功能,你没有实现它。

GIL: http://en.wikipedia.org/wiki/Global_Interpreter_Lock

现在,关于你正在实施的锁:

threading.Lock() - 返回新原始锁定对象的工厂函数。一旦线程获得它,后续尝试获取 阻止,直到它被释放;任何线程都可以释放它。

请参阅线程的官方文档:https://docs.python.org/2/library/threading.html

一般来说,当您将某些资源锁定到关键部分时,此资源仅对必须获取锁以访问共享资源的线程锁定。在您的示例中,函数b在写入stdout之前不会尝试获取锁定。

此外,我相当肯定这不会像你期望的那样工作,无论如何输出都会混淆,因为stdout没有被锁定。要获得干净的输出,您可以让线程将消息传递给某个线程安全的共享队列,然后只有一个线程从该队列写入stdout。

答案 1 :(得分:1)

threading.Lock根本不影响标准输出的使用。它只用于创建所谓的关键部分,其中一次只有一个线程可以在由同一个锁实例保护的所有关键部分中执行代码。

如果你需要序列化输出,你必须自己实现,可能是基于锁或其他一些机制。

例如,您可以使用一个日志记录类来缓存其他线程的日志记录,同时保留一些锁定,但这并非易事,因为日志记录类不能“检查”某个锁是否正在使用,因为导致竞争条件。通常阻止日志记录不是一个好主意。但也许你正在考虑使用stdout。通常,如果您尝试在多线程程序中生成特定的stdout,则可能应该明确地对所有输出使用锁定或将输出的使用限制为仅一个线程。为了限制输出到一个线程,queue.Queue可以帮助多个线程生成完整的部分,然后由一个线程一次打印一个部分。