首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >致命的Python错误和`BufferedWriter`

致命的Python错误和`BufferedWriter`
EN

Stack Overflow用户
提问于 2017-07-24 00:35:36
回答 1查看 10.7K关注 0票数 30

我在文档中看到了这段话,上面写道:

二进制缓冲对象( BufferedReaderBufferedWriterBufferedRandomBufferedRWPair的实例)使用锁保护其内部结构;因此,从多个线程同时调用它们是安全的。

我不确定为什么他们需要“保护”他们的内部结构,因为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以及对这些对象BufferedReaderBufferedWriterBufferedRandomBufferedRWPairflush调用。

1)在Linux上,可能在Windows上,当主线程退出时,它的子线程也会终止。这对上述行为有何影响?如果主线程能够在其时间片期间退出,则在与另一个线程进行上下文切换之前,不会发生致命错误,因为所有线程都被终止。然而,没有任何东西可以保证主线程一启动就会退出。

2)致命错误发生在解释器的完成过程(关闭)与readwriteflush调用以及对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的锁,这会导致致命错误。多次运行此代码以注意其不同的行为。

EN

回答 1

Stack Overflow用户

发布于 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

  • 当主线程退出时,其他线程是否存活由系统定义。在大多数系统上,它们在没有执行try的情况下被杀死...finally子句或执行对象析构函数。
  • 当主线程退出时,它不会执行任何通常的清理操作(除了try ...最后子句),并且不刷新标准I/O文件。

也许你应该使用更高级别的threading module,并在主线程和其他线程之间进行适当的同步。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45267439

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档