dir*_*obs 24 python linux multithreading python-2.7 python-internals
我在文件中发现了这一段,其中说:
二进制缓冲对象(的实例
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")
Run Code Online (Sandbox Code Playgroud)
在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
Run Code Online (Sandbox Code Playgroud)
在Python 2.7下,没有错误.我不知道为什么会发生这种情况,但是,我一直在寻找bufferedio.c.另一个代码的行为类似于在Python 3.X上测试过的上述代码片段,有时我得到了Fatal Python error
,有时我没有.任何带有循环加号的线程函数std[out][err].write
都会导致此致命错误.很难定义这个错误的特征,据我所知,文档没有提到它的任何内容.我不确定即使它是一个错误,我希望不是.
我对这种行为的解释是这样的,*我可能是完全错误的:主线程在其持有锁定时退出sys.stdout.buffer
.但是,这似乎与以下事实相反:当主线程退出我正在运行Python,Linux的系统时,线程终止.
我发布这个作为答案,它只是不能在评论部分完成.
此行为并不仅仅限于write
它的影响read
,以及flush
对这些对象的调用BufferedReader
,BufferedWriter
,BufferedRandom
和BufferedRWPair
.
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)
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,如果主线程一启动就退出,就是这样,不会发生致命错误,并且所有生成的线程都会立即终止(至少在Linux中)这是平台相关的.如果你运气不够并且在主线程退出之前另一个线程开始在该字段上播放,没有os._exit(0)
调用,解释器将完成其正常的终结周期以获取锁定, sys.stdout.buffer
从而导致致命错误.多次运行此代码以注意其不同的行为.
mrn*_*sco 11
你的问题与锁定内容没有严格的关系,但事实上你正试图写一个不存在stdout
的问题daemon thread
.
当您运行主脚本时,Python解释器启动并执行打开stdout
文件描述符的代码.
当脚本结束而不等待线程完成时:
stdout
stdout
因为前一步骤无法访问该锁定为了避免这个问题,您可以写入文件而不是stdout(作为守护程序线程应该这样做)或者只是等待线程完成以下内容:
from threading import Thread
import time
def start():
for i in range(10):
print("SPAM SPAM SPAM!")
# create a thread list (you'll need it later)
threads = [Thread(target=start, args=()) for i in range(10)]
# start all the threads
for t in threads:
t.start()
# or [t.start() for t in threads] if you prefer the inlines
time.sleep(0.0001)
# wait for threads to finish
for t in threads:
t.join()
# or [t.join() for t in threads] for the inline version
print("main thread exited")
Run Code Online (Sandbox Code Playgroud)
当我在windows(cygwin)上运行第一个代码时,我在python3上得到了错误,但我在python2上也出错了
> Unhandled exception in thread started by
> sys.excepthook is missing
> lost sys.stderr
Run Code Online (Sandbox Code Playgroud)
所以有可能在你的平台上python2.x可能在它们无法获取锁时无声地退出线程.另外我认为_thread模块(2.7中的线程)是一个低级模块,并不保证避免这种行为.从模块帮助
- 当主线程退出时,系统定义其他线程是否存活.在大多数系统上,它们在没有执行try ... finally子句或执行对象析构函数的情况下被杀死.
- 当主线程退出时,它不执行任何常规清理(除了try ... finally子句被尊重),并且标准I/O文件不会被刷新.
也许你应该使用更高级别的线程模块,在主线程和其他线程之间进行适当的同步.
归档时间: |
|
查看次数: |
3993 次 |
最近记录: |