【问题标题】:popen with python read and write blocks, python2.7用python读写块弹出,python2.7
【发布时间】:2017-03-23 19:04:45
【问题描述】:

我知道这个问题已经被问过很多次了,但是我的问题是不同的,因为我使用的是第三方代码并且不能修改太多。 我有一个在代码中多次调用的函数来创建一个子进程,将数据写入标准输入然后读取。它只是挂在这一行

line = self.classifier.stderr.readline()

使用 popen.communicate 确实解决了这个问题,但是由于 func2(classifier, vectors) 需要多次调用,所以会引发异常

  subprocess I/O operation on closed file  

有没有办法执行非阻塞读取操作?

def func1 (extcmd):
                cmd=extcmd
                classifier = subprocess.Popen(self.classifier_cmd, shell = True, stdin = subprocess.PIPE, stderr = subprocess.PIPE) 
                if self.classifier.poll():
                    raise OSError('Could not create classifier subprocess')
                return classifier

def func2(classifier, vectors):
                        classifier.stdin.write('\n'.join(vectors) + "\n\n")
                        lines = []
                        line = self.classifier.stderr.readline()
                        print("not reaching")
                        while (line.strip() != ''):
                #            print line
                            lines.append(line)
                            line = self.classifier.stderr.readline()

 if __name__ == '__main__':
                extcmd="some external shell script"
                vectors="some results"
                classifier=func1(extcmd)
                func2(classifier, vectors)

修改代码以添加更多细节

import subprocess
import paths
import os.path

class CRFClassifier:
    def __init__(self, name, model_type, model_path, model_file, verbose):
        self.verbose = verbose
        self.name = name
        self.type = model_type
        self.model_fname = model_file
        self.model_path = model_path

        if not os.path.exists(os.path.join(self.model_path, self.model_fname)):
            print 'The model path %s for CRF classifier %s does not exist.' % (os.path.join(self.model_path, self.model_fname), name)
            raise OSError('Could not create classifier subprocess')


        self.classifier_cmd = '%s/crfsuite-stdin tag -pi -m %s -' % (paths.CRFSUITE_PATH, 
                             os.path.join(self.model_path, self.model_fname))
#        print self.classifier_cmd
        self.classifier = subprocess.Popen(self.classifier_cmd, shell = True, stdin = subprocess.PIPE, stderr = subprocess.PIPE)

        if self.classifier.poll():
            raise OSError('Could not create classifier subprocess, with error info:\n%s' % self.classifier.stderr.readline())

        #self.cnt = 0


    def classify(self, vectors):
#        print '\n'.join(vectors) + "\n\n"

        self.classifier.stdin.write('\n'.join(vectors) + "\n\n")

        lines = []
        line = self.classifier.stderr.readline()
        while (line.strip() != ''):
#            print line
            lines.append(line)
            line = self.classifier.stderr.readline()


        if self.classifier.poll():
            raise OSError('crf_classifier subprocess died')

        predictions = []
        for line in lines[1 : ]:
            line = line.strip()
#            print line
            if line != '':
                fields = line.split(':')
#                print fields
                label = fields[0]
                prob = float(fields[1])
                predictions.append((label, prob))

        seq_prob = float(lines[0].split('\t')[1])

        return seq_prob, predictions


    def poll(self):
        """
        Checks that the classifier processes are still alive
        """
        if self.classifier is None:
            return True
        else:
            return self.classifier.poll() != None

为输入文件创建分类器对象,该文件是包含句子列表的文档,并且在创建时它还使用此句子列表执行外部命令。然后在一个单独的函数中处理每个句子,为每个句子提供一个单独的向量。这个新向量被传递给分类函数。

def func2():
    classifier=create a classifier object for an input file, this executes the external command
    for sentence in sentences:
        vectors=process(sentence)# some external function
        classifier.classify(features)                    

【问题讨论】:

标签: python subprocess deadlock popen


【解决方案1】:

缩进?看起来 func1 在 func2 开始做任何事情之前以 return 语句退出。将所有从 func2 开始的所有内容移到左侧一个选项卡,看看会发生什么。或者,问题可能出在其他地方 - 您只是没有正确粘贴代码。

【讨论】:

  • 抱歉。我现在已经正确格式化了。我知道问题是由于死锁造成的,但我无法使用通信,因为 func2 被多次调用。
【解决方案2】:

这是你的答案吗(来自https://docs.python.org/2/library/subprocess.html)? 注意 请勿将此函数与 stdout=PIPE 或 stderr=PIPE 一起使用,因为这可能会基于子进程输出量而死锁。当你需要管道时,使用 Popen 和communicate() 方法。

【讨论】:

  • 是的,我第一次阅读并使用了通信工作,但是 func2 被多次调用,如果我使用通信,它第二次失败并出现错误 ValueError: I/O operation on closed文件。我正在阅读可以使用的选择,但我不确定如何在不搞砸的情况下使用它。
【解决方案3】:

您说您不能对代码进行太多更改,但也许您可以稍微更改一下:) 尝试编写一个块来找出正在使用的“向量”并使用不同的。

【讨论】:

  • 我不太愿意修改它,因为它是一个很大的代码库,我不确定它会产生什么影响。当你谈到向量时,你能多解释一下或举一些例子吗?我调试了代码,这就是它的工作原理。 func1 执行带有句子列表的命令。然后对作为向量输入的每个句子迭代调用 func2 以读取结果。因此,如果我使用通信,它适用于第一句话,然后因错误而失败。
  • func1中如何使用“cmd”?
  • 好的,有点太深了。我会在这里给你我最后的 2 美分。您是说当您多次调用 func2 并出现错误时会出现问题。我只是添加一个检查文件是否被另一个进程使用(这就是我在错误消息中解释“关闭”的方式 - 可能是由于 GIL),如果是,请尝试创建一个深层副本并稍后丢弃它。抱歉,我想我不能提供更多 - 祝你好运。
  • 谢谢,我试试
猜你喜欢
  • 2017-07-07
  • 1970-01-01
  • 2015-04-21
  • 1970-01-01
  • 2020-11-21
  • 1970-01-01
  • 2017-06-12
  • 2017-09-06
  • 1970-01-01
相关资源
最近更新 更多