我正在尝试让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()
):
def download(self):
#print("connected")
self.server = FTP(**self.serverDetails)
self.server.login(**self.userDetails)
self.server.cwd("/public_html/uploads") #changing to /pub/unix
#print "File List: \n"
files = []
successful = [0]
unsuccessful = [0]
self.server.retrlines("NLST",files.append)
for f in files:
if(f != '.' and f != '..'):
#print("downloading:\t"+f)
local_filename = os.path.join(mw._['cwd']+"media", f)
with open(local_filename, "wb") as i:
self.server.retrbinary("RETR " + f, i.write)
#print("\t| Success")
successful.append(f)
for f in files:
if(f != '.' and f != '..' and f not in successful):
unsuccessful.append(f)
return (successful, unsuccessful)
我得到的输出是:
Successful:
Unsuccessful: None
successful
的值为None
。
答案 0 :(得分:0)
如果您确实使用subprocess.call()
工作,那么您可以继续使用它 - 因为call()
在内部使用Popen()
- 所以dwnldMedia.py
是已经作为单独的子进程(你称之为新线程)运行,因此代码执行方面不会因为调用代码而被更改{{1}直接
无论您使用Popen()
还是call()
+ Popen()
,下载都不会同时发生(我认为这是您的目标),因为两者都会在继续之前等待脚本完成执行。对于并发下载,您需要使用communicate()
模块执行多任务。由于您正在进行I / O绑定,因此也可以使用multiprocessing
和/或thread
模块完成并发下载(因为它可以更简单地共享数据)所有这些都在同一个过程中。)
话虽如此,所以这实际上是对您的问题的回答,这里是如何使用从threading
返回的结果并将数据从一个进程传递到另一个进程。您不能将简单subprocess.communicate()
结果从一个进程转移到另一个进程,因为它们位于不同的地址空间中。一种方法是使用#34; pipe"他们之间的数据。 return
收集收到的所有数据,并在返回时将其作为两个字符串的元组返回,一个用于communicate()
,另一个用于stderr
。
该示例使用stderr
将发送的数据转换为可以在接收端的Python对象中返回的内容。 pickle
模块同样运作良好。我不得不从你问题中的例子中删除相当数量的代码来制作我可以运行和测试的东西,但是试图在下面的内容中保持整体结构的完整。
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()
脚本中download()
方法的精简版本:
dwnldMedia.py