Python tempfile模块与线程不兼容;我哪里出错了?
我在使用Python的线程和临时文件模块时遇到了一个有趣的问题。似乎有些东西在线程退出之前没有被清理干净,而我又碰到了打开文件数量的限制。(这是在OS X 10.5.8上,使用Python 2.5.1。)
不过,如果我自己模仿一下临时文件模块的做法(虽然没有进行所有的安全检查,但只是生成一个文件描述符,然后用os.fdopen来创建一个文件对象),我就没有问题。
在我把这个问题提交给Python作为一个bug之前,我想先在这里问问,因为我更可能是哪里做错了。但如果真是这样,经过一天的尝试,我还是没找到原因。
#!/usr/bin/python
import threading
import thread
import tempfile
import os
import time
import sys
NUM_THREADS = 10000
def worker_tempfile():
tempfd, tempfn = tempfile.mkstemp()
tempobj = os.fdopen(tempfd, 'wb')
tempobj.write('hello, world')
tempobj.close()
os.remove(tempfn)
time.sleep(10)
def worker_notempfile(index):
tempfn = str(index) + '.txt'
# The values I'm passing os.open may be different than tempfile.mkstemp
# uses, but it works this way as does using the open() function to create
# a file object directly.
tempfd = os.open(tempfn,
os.O_EXCL | os.O_CREAT | os.O_TRUNC | os.O_RDWR)
tempobj = os.fdopen(tempfd, 'wb')
tempobj.write('hello, world')
tempobj.close()
os.remove(tempfn)
time.sleep(10)
def main():
for count in range(NUM_THREADS):
if count % 100 == 0:
print('Opening thread %s' % count)
wthread = threading.Thread(target=worker_tempfile)
#wthread = threading.Thread(target=worker_notempfile, args=(count,))
started = False
while not started:
try:
wthread.start()
started = True
except thread.error:
print('failed starting thread %s; sleeping' % count)
time.sleep(3)
if __name__ == '__main__':
main()
如果我运行时激活了worker_notempfile
这一行,而把worker_tempfile
这一行注释掉,它就能正常完成。
反过来(使用worker_tempfile
),我就会遇到以下错误:
$ python threadtempfiletest.py
Opening thread 0
Opening thread 100
Opening thread 200
Opening thread 300
Exception in thread Thread-301:
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/threading.py", line 460, in __bootstrap
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/threading.py", line 440, in run
File "threadtempfiletest.py", line 17, in worker_tempfile
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/tempfile.py", line 302, in mkstemp
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/tempfile.py", line 236, in _mkstemp_inner
OSError: [Errno 24] Too many open files: '/var/folders/4L/4LtD6bCvEoipksvnAcJ2Ok+++Tk/-Tmp-/tmpJ6wjV0'
有没有人知道我哪里做错了?这是Python的bug,还是我太笨了?
更新 2009-12-14: 我想我找到了答案,但我不喜欢这个结果。因为没有人能重现这个问题,我开始在办公室里找机器。除了我的机器,其他的都能通过测试。我在一台使用相同软件版本的Mac上测试过,甚至还找了一台硬件和软件配置完全相同的Desktop G5——结果也是一样。两个测试(使用临时文件和不使用临时文件)在所有机器上都成功了。
为了好玩,我下载了Python 2.6.4,在我的桌面上试了一下,结果和Python 2.5.1一样:临时文件失败,不使用临时文件成功。
这让我得出结论,我的Mac上可能出了问题,但我实在搞不清楚是什么。欢迎任何建议。
5 个回答
我觉得你的问题可以在这里找到答案。你需要明确地使用os.close()
来关闭mkstemp
返回的元组中的第一个部分,也就是文件描述符。
补充说明:不,提问者已经在做应该做的事情了。我把这个回答保留在这里是为了那个不错的链接。
我在Mac OS X 10.5.9上用苹果自己提供的Python 2.5.1测试时,没有遇到任何问题,运行得很好!
我在一台Macbook Pro(用的是Intel处理器)和一台老旧的PowerMac(用的是PPC处理器)上都试过了。
所以我猜可能是10.5.8版本里有个我没注意到的bug(我手头没有10.5.8的系统可以测试,因为每次软件更新我都会及时升级)。我建议你试试升级到10.5.9,看看问题是否消失。如果问题依然存在,我就不知道为什么我的机器和你的机器会有这样的不同表现了。
因为没有人能重现这个问题,所以我开始在办公室里找机器测试。结果除了我的机器,其他的都能正常运行。我还在一台和我用的版本完全一样的Mac上测试过,结果也是一样。我甚至找了一台硬件和软件配置完全相同的Desktop G5,结果也是一样。无论是用tempfile还是不用tempfile,其他机器上的测试都成功了。
为了好玩,我下载了Python 2.6.4,在我的桌面上试了一下,结果和Python 2.5.1一样:用tempfile失败,不用tempfile成功。
这让我得出一个结论:我的Mac上可能有什么问题,所以这应该不是其他人会遇到的问题。
非常感谢所有帮助过我的人(特别是Alex Martelli)!