6

我对 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 上使用与我使用的相同软件版本进行了测试。我什至去寻找与我拥有完全相同的硬件和软件配置的 Desktop G5 —— 相同的结果。两个测试(使用临时文件和没有临时文件)都成功了。

为了踢球,我下载了 Python 2.6.4,并在我的桌面上尝试了它,并且在我的系统上使用了与 Python 2.5.1 相同的模式:tempfile failed,并且 notempfile 成功。

这使我得出结论,我的 Mac 上出现了一些问题,但我肯定不知道是什么。欢迎任何建议。

4

5 回答 5

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 并查看错误是否消失 - 如果没有,我不知道我的机器和您的机器之间的这种行为差异是如何可能的。

于 2009-12-13T05:53:26.843 回答
3

我想你的答案可以在这里找到。您必须明确os.close()给出作为给您的元组的第一部分的文件描述符mkstemp

编辑:不,OP已经在做应该做的事情。我将答案留给漂亮的链接。

于 2009-12-13T02:49:11.640 回答
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语句应该确保文件对象无论如何都被关闭。也许它可能会有所帮助?

祝你好运。顺便说一句,在这个问题上做得很好。

于 2009-12-13T08:35:12.477 回答
1

为什么你认为这个错误不是真的?您正在启动 10000 个线程,每个线程打开一个文件,而在 Unix 系统下,打开文件的最大数量通常为 1024。

首先尝试手动跟踪当前打开的文件数量,并检查它是否超过了操作系统限制。

于 2009-12-13T22:28:52.820 回答
0

由于没有人能够复制这个问题,我在我们的办公室四处寻找机器。它传递了除了我的机器之外的所有东西。我在 Mac 上使用与我使用的相同软件版本进行了测试。我什至去寻找与我拥有完全相同的硬件和软件配置的 Desktop G5 —— 相同的结果。两个测试(使用临时文件和没有临时文件)都成功了。

为了踢球,我下载了 Python 2.6.4,并在我的桌面上尝试了它,并且在我的系统上使用了与 Python 2.5.1 相同的模式:tempfile failed,并且 notempfile 成功。

这让我得出结论,我的 Mac 上出现了问题,所以这不太可能是其他人遇到的问题。

非常感谢为此提供帮助的所有人(尤其是 Alex Martelli)!

于 2009-12-15T00:36:07.647 回答