我在文档中看到了这段话,上面写道:
二进制缓冲对象(
BufferedReader
、BufferedWriter
、BufferedRandom
和BufferedRWPair
的实例)使用锁保护其内部结构;因此,从多个线程同时调用它们是安全的。
我不确定为什么他们需要“保护”他们的内部结构,因为GIL正在发挥作用。谁在乎?我并不太在意,直到我发现这个锁有一些意义,考虑这段代码:
from _thread import start_new_thread
import time
def start():
for i in range(10):
print("SPAM SPAM SPAM!")
for i in range(10):
start_new_thread(start, ())
time.sleep(0.0001)
print("main thread exited")
在Python 3.x上运行时的输出:
...many SPAM...
SPAM SPAM SPAM!
SPAM SPAM SPAM!
SPAM SPAM SPAM!
main thread exited
SPAM SPAM SPAM!
SPAM SPAM SPAM!
SPAM SPAM SPAM!
SPAM SPAM SPAM!
SPAM SPAM SPAM!
Fatal Python error: could not acquire lock for
<_io.BufferedWritername='<stdout>'> at interpreter shutdown, possibly due to daemon threads
在Python 2.7下,没有错误。我不知道为什么会发生这种情况,但是,我已经在bufferedio.c上到处寻找了。在Python3.x上测试的另一个代码行为类似于上面的代码片段,有时我得到Fatal Python error
,有时我没有。任何带有循环和std[out][err].write
的线程函数都会导致这个致命错误。很难定义这个错误的特征,据我所知,文档中没有提到任何关于它的内容。我不确定这是不是一个bug,我希望不是。
我对这种行为的解释是这样的:*我可能完全错了:主线程在持有sys.stdout.buffer
的锁时退出了。然而,这似乎与以下事实相反:在我运行Python的Linux系统上,当主线程退出时,线程就会终止。
我将此作为答案发布,它不能在评论区中完成。
此行为不仅限于write
,它还会影响read
以及对这些对象BufferedReader
、BufferedWriter
、BufferedRandom
和BufferedRWPair
的flush
调用。
1)在Linux上,可能在Windows上,当主线程退出时,它的子线程也会终止。这对上述行为有何影响?如果主线程能够在其时间片期间退出,则在与另一个线程进行上下文切换之前,不会发生致命错误,因为所有线程都被终止。然而,没有任何东西可以保证主线程一启动就会退出。
2)致命错误发生在解释器的完成过程(关闭)与read
、write
或flush
调用以及对Buffered*
对象的其他可能操作之间。终结过程获取这些对象的锁,任何write
,例如对BufferedWriter
对象的任何调用都会导致Fatal Python error
。
os._exit
在没有终结化步骤的情况下终止解释器,因此解释器将不拥有我们正在讨论的对象的锁,这是另一个示例:
from _thread import start_new_thread
import time, sys, os
def start(myId):
for i in range(10):
sys.stdout.buffer.write(b"SPAM\n")
for i in range(2):
start_new_thread(start, (i,))
x = print("main thread")
print(x)
#os._exit(0)
在上面的代码中,如果主线程一启动就退出,那么就不会发生致命错误,所有产生的线程都会立即终止(至少在Linux中是这样),但这是与平台相关的。如果你够倒霉,另一个线程在主线程退出之前就开始在字段上运行,那么在没有os._exit(0)
调用的情况下,解释器会通过正常的结束周期来获取sys.stdout.buffer
的锁,这会导致致命错误。多次运行此代码以注意其不同的行为。
发布于 2017-07-24 12:44:20
当我在python2 (cygwin)上运行第一个代码时,我在python3上得到了错误,但我在windows上也得到了一个错误
> Unhandled exception in thread started by
> sys.excepthook is missing
> lost sys.stderr
因此,在您的平台上,当线程无法获得锁时,python2.x可能会静默退出线程。另外,我认为_thread module (2.7中的线程)是一个低级模块,不能保证避免这种行为。从module help
也许你应该使用更高级别的threading module,并在主线程和其他线程之间进行适当的同步。
https://stackoverflow.com/questions/45267439
复制相似问题