0

给定函数

def get_files_from_sha(sha, files):
    from subprocess import Popen, PIPE
    import tarfile
    if 0 == len(files):
        return {}
    p = Popen(["git", "archive", sha], bufsize=10240, stdin=PIPE, stdout=PIPE, stderr=PIPE)
    tar = tarfile.open(fileobj=p.stdout, mode='r|')
    p.communicate()
    contents = {}
    doall = files == '*'
    if not doall:
        files = set(files)
    for entry in tar:
        if (isinstance(files, set) and entry.name in files) or doall:
            tf = tar.extractfile(entry)
            contents[entry.name] = tf.read()
            if not doall:
                files.discard(entry.name)

    if not doall:
        for fname in files:
            contents[fname] = None
    tar.close()
    return contents

在循环中调用 的某些值sha,一段时间后(在我的情况下,4 次迭代)它在调用 时开始失败tf.read(),并显示以下消息:

Traceback (most recent call last):
  File "../yap-analysis/extract.py", line 243, in <module>
    commits, identities, identities_by_name, identities_by_email, identities_freq = build_commits(commits)
  File "../yap-analysis/extract.py", line 186, in build_commits
    commit = get_commit(commit)
  File "../yap-analysis/extract.py", line 84, in get_commit
    contents = get_files_from_sha(commit['sha'], files)
  File "../yap-analysis/extract.py", line 42, in get_files_from_sha
    contents[entry.name] = tf.read()
  File "/usr/lib/python2.7/tarfile.py", line 817, in read
    buf += self.fileobj.read()
  File "/usr/lib/python2.7/tarfile.py", line 737, in read
    return self.readnormal(size)
  File "/usr/lib/python2.7/tarfile.py", line 746, in readnormal
    return self.fileobj.read(size)
  File "/usr/lib/python2.7/tarfile.py", line 573, in read
    buf = self._read(size)
  File "/usr/lib/python2.7/tarfile.py", line 581, in _read
    return self.__read(size)
  File "/usr/lib/python2.7/tarfile.py", line 606, in __read
    buf = self.fileobj.read(self.bufsize)


ValueError: I/O operation on closed file

我怀疑子进程尝试进行一些并行化(?)。

真正的原因是什么以及如何在python2上以一种干净而健壮的方式解决它?

4

2 回答 2

1

我认为你的问题是p.communicate(). 此方法发送到标准输入,从标准输出和标准错误(您没有捕获)读取并等待进程终止。

tarfile正在尝试从进程 stdout 中读取,并且当它这样做时,进程已完成,因此出现错误。

我没有尝试运行您的代码(我无权访问git),但您可能根本不想要p.communicate,请尝试将其注释掉。

于 2012-12-02T11:56:24.843 回答
1

不要.communicate()Popen实例上使用;它会读取stdout流直到完成。从文档中:

与进程交互:将数据发送到标准输入。从 stdout 和 stderr 读取数据,直到到达文件结尾。

代码.communicate()甚至在管道.close()上添加了显式调用。stdout

只需删除对的调用就.communicate()足够了,但在阅读 tarfile 内容.wait() 后也要添加:

tar.close()
p.stdout.close()
p.wait()

可能tar.close()也关闭p.stdout了,但是那里的额外内容.close()不应该受到伤害。

于 2012-12-02T11:56:49.540 回答