我遇到了一个有趣的线程问题和Python中的tempfile模块。在线程退出之前,某些东西似乎没有得到清理,而且我正在针对打开的文件限制运行。 (这是在OS X 10.5.8,Python 2.5.1上。)
然而,如果我复制tempfile模块正在做什么(不是所有的安全检查,而只是生成文件描述符,然后使用os.fdopen来生成文件对象),我没有问题。
在将此作为Python的错误提交之前,我想我会在这里查看,因为我更有可能做了一些巧妙的错误。但是,如果我是这样,那一天试图解决这个问题并没有把我带到任何地方。
#!/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中的一个错误,还是我头脑发热?
更新2009-12-14: 我想我找到了答案,但我不喜欢它。由于没有人能够复制这个问题,我去办公室寻找机器。除了我的机器,它传递了一切。我在Mac上使用与我使用的相同软件版本进行了测试。我甚至用我所拥有的完全相同的硬件和软件配置来寻找桌面G5 - 结果相同。两个测试(使用tempfile和没有tempfile)都成功了。
对于踢,我下载了Python 2.6.4,并在我的桌面上尝试了它,我的系统上的模式与Python 2.5.1相同:tempfile失败,并且notempfile成功。
这让我得出的结论是我的Mac上出现了一些东西,但我肯定无法弄清楚是什么。欢迎任何建议。
答案 0 :(得分:4)
我无法在Mac OS X 10.5.9上重现(Apple自己构建的)Python 2.5.1的问题 - 运行完成就好了!
我已经在Macbook Pro(即Intel处理器)和旧的PowerMac(即PPC处理器)上尝试过。
所以我只能想象10.5.8中一定有一个我从未注意到的错误(没有任何10.5.8可以测试,因为我总是在软件更新提供的时候立即升级)。我可以建议你尝试升级到10.5.9并查看错误是否消失 - 如果没有,我不知道我的机器和你的机器之间的这种行为差异是可能的。
答案 1 :(得分:3)
我认为你的答案可以找到here。您必须明确os.close()
作为mkstemp
为您提供的元组的第一部分给出的文件描述符。
编辑:不,OP已经在做应该做的事了。我正在为这个很好的链接留下答案。
答案 2 :(得分:1)
我刚刚在我的Ubuntu Linux计算机上测试了你的代码,它对我来说非常适合。
我有一个建议让你试试。我不知道它会有所帮助,但它不会伤害。重写您的代码以用于:
from __future__ import with_statement
def worker_tempfile():
tempfd, tempfn = tempfile.mkstemp()
with os.fdopen(tempfd, 'wb') as tempobj:
tempobj.write('hello, world')
os.remove(tempfn)
time.sleep(10)
with
语句应该确保文件对象无论如何都会被关闭。也许它可能会有所帮助?
答案 3 :(得分:1)
为什么你认为错误不是真的?您正在启动10000个线程,每个线程都打开一个文件,而Unix系统下打开的最大文件数通常是1024个。
首先尝试手动跟踪当前打开的文件数量,并检查它是否超过操作系统限制。
答案 4 :(得分:0)
由于没有人能够复制这个问题,我去办公室寻找机器。除了我的机器,它传递了一切。我在Mac上使用与我使用的相同软件版本进行了测试。我甚至用我所拥有的完全相同的硬件和软件配置来寻找桌面G5 - 结果相同。两个测试(使用tempfile和没有tempfile)都成功了。
对于踢,我下载了Python 2.6.4,并在我的桌面上尝试了它,我的系统上的模式与Python 2.5.1相同:tempfile失败,并且notempfile成功。
这让我得出的结论是我的Mac上出现了一些东西,所以这不可能成为其他任何人遇到过的问题。
非常感谢所有人(特别是Alex Martelli)为此提供了帮助!