如何获得子流程.Popen正确工作?

2024-10-03 04:24:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图使subprocess.Popen()正常工作,但由于某些原因返回的值完全错误。在

该脚本打开一个从服务器下载文件的FTP连接脚本,然后返回成功下载和未成功下载文件的元组。这个脚本在使用subprocess.call()之前已经起作用了,但是我想使用Popen(),这样它调用的脚本就在另一个线程中,不会干扰主程序。在

这是我的主修课:

def FTPDownload(self):
    try:
        ftpReq = subprocess.Popen(['Python', mw._['cwd']+"dwnldMedia.py"],
                                  shell=True,
                                  stdout=subprocess.PIPE)
        successful, unsuccessful = ftpReq.communicate()
        self.consPrompt("Successful:\t"+str(successful))
        self.consPrompt("Unsuccessful:\t"+str(unsuccessful))
    except subprocess.CalledProcessError as e:
        self.consPrompt((cp._['E0']).format(str(e)))

这里是dwnldMedia.py__init__调用download()):

^{pr2}$

我得到的输出是:

Successful:
Unsuccessful:   None

其中successful的值为None。在


Tags: 文件pyself脚本nonesubprocesspopenstr
1条回答
网友
1楼 · 发布于 2024-10-03 04:24:56

如果你真的用^{}来工作,你也可以继续使用它-因为call()在内部使用Popen(),所以{}已经是作为一个单独的子进程运行的(你称之为新线程),因此,直接调用Popen()不会改变代码执行的这一方面。在

无论您使用call()还是Popen()+communicate(),下载都不会同时进行(我假设这是您的目标),因为两者都会在继续之前等待脚本完成执行。对于并发下载,您需要使用multiprocessing模块执行多任务。由于您所做的是I/O绑定的,并发下载也可以使用thread和/或threading模块完成(共享数据通常更简单,因为数据都在同一个进程中)。在

话虽如此,这实际上是对您问题的回答,下面是如何使用subprocess.communicate()返回的结果,并将数据从一个进程传递到另一个进程。不能简单地从一个进程到另一个进程的return结果,因为它们位于不同的地址空间中。一种方法是在它们之间“管道”数据。communicate()收集接收到的所有数据,并在返回时作为两个字符串的元组返回,一个用于stderr,另一个用于stderr。在

该示例使用pickle将发送的数据转换为接收端的Python对象中可以返回的数据。json模块也同样工作良好。我不得不从你问题中的例子中删除大量的代码来做一些我可以运行和测试的东西,但是我已经尝试在下面的内容中保持整体结构的完整性。在

import cPickle as pickle
import subprocess

class SomeClass(object):
    def FTPDownload(self):
        try:
            # The -u argument puts stdin, stdout and stderr into binary mode
            # (as well an makes them unbuffered). This is needed to avoid
            # an issue with writing pickle data to streams in text mode
            # on Windows.
            ftpReq = subprocess.Popen(['python', '-u', 'dwnldMedia.py'],
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE)
            stdout, stderr = ftpReq.communicate()
            if stdout:
                # convert object returned into a Python obj
                results = pickle.loads(stdout)
                print('  successful: {successful}'.format(**results))
                print('unsuccessful: {unsuccessful}'.format(**results))
            if stderr:
                print("stderr:\n{}".format(stderr))
        except subprocess.CalledProcessError as exception:
            print('exception: {}'.format(str(exception)))

if __name__ == '__main__':
    instance = SomeClass()
    instance.FTPDownload()

下面是dwnldMedia.py脚本中download()方法的精简版本:

^{pr2}$

相关问题 更多 >