2013-07-26 59 views
2

我知道这个问题的一部分已经被问过,但我有一些相关的问题。python subprocess和mysqldump

我试图执行

mysqldump -u uname -ppassword --add-drop-database --databases databaseName | gzip > fileName 

我可能倾倒非常大(200GB?)分贝。这本身就是一件愚蠢的事情吗?然后我想通过网络发送压缩文件进行存储,删除本地转储,并清除一些表格。

无论如何,我正在使用这样的子进程,因为似乎没有办法在没有子进程的情况下执行整个原始调用。以表格名称。:

from subprocess import Popen, PIPE 

f = open(FILENAME, 'wb') 
args = ['mysqldump', '-u', 'UNAME', '-pPASSWORD', '--add-drop-database', '--databases', 'DB'] 

p1 = Popen(args, stdout=PIPE) 
P2 = Popen('gzip', stdin=p1.stdout, stdout=f) 
p2.communicate() 

但后来我读了通信缓存数据在内存中,这对我不起作用。这是真的?

我终于实现了,现在是什么:当然

import gzip 
subprocess.call(args, stdout=f) 
f.close() 

f = open(filename, 'rb') 
zipFilename = filename + '.gz' 
f2 = gzip.open(zipFilename, 'wb') 
f2.writelines(f) 
f2.close() 
f.close() 

这需要一万年,我恨它。

我的问题: 1.我可以在非常大的分贝上使用我的第一种方法吗? 2.我能否将mysqldump的输出传输到套接字并在网络上触发它并在到达时保存它,而不是发送压缩文件?

谢谢!

+0

相关:我如何使用subprocess.Popen连接管由多个进程?](http://stackoverflow.com/q/295459/4279) – jfs

回答

5

你不需要沟通()。如果您想读取stdout/stderr来完成,那么它仅作为一种方便的方法。但是,既然你是链接命令,他们正在为你做。等待他们完成。

from subprocess import Popen, PIPE 

args = ['mysqldump', '-u', 'UNAME', '-pPASSWORD', '--add-drop-database', '--databases', 'DB'] 

with open(FILENAME, 'wb', 0) as f: 
    p1 = Popen(args, stdout=PIPE) 
    p2 = Popen('gzip', stdin=p1.stdout, stdout=f) 
p1.stdout.close() # force write error (/SIGPIPE) if p2 dies 
p2.wait() 
p1.wait() 
+0

谢谢。这就是我要找的! – Zobal

1

烨数据缓存在内存中:

“注意读取的数据在内存中缓冲,因此,如果数据量很大或无限不要使用此方法 。” - subprocess docs

不幸的是目前没有办法以异步方式使用POPEN:PEP3145

,而不是做这一切在Python中,你可以手动执行

os.system("mysqldump -u uname -ppassword --add-drop-database --databases databaseName | gzip > fileName 

“)

当然用适当的字符串替换使用string.format;否则你会给计算机带来不必要的压力,特别是试图通过管道沟通200GB ...

你能详细说明你正在尝试做什么吗?现在,这听起来像是你在同一台计算机上倾倒和压缩。


是的,你可以通过网络流文件。我不知道,如果你想直接流的MySQL的直接输出,但 - 你可能要考虑之前看看你的网络功能,


庆典:

#!/bin/bash 
mysqldump -u uname -ppassword --add-drop-database --databases databaseName | gzip > fileName 
#transfer fileName to other computer 

^你也可以把它放在一个crontab中,让它每隔一段时间运行:)

+0

这里的情况: – Zobal

+0

请不要'os.system()'... – glglgl

+0

我收集数据到系统的数据库。当磁盘达到某个阈值时,我想将压缩转储移到另一个系统,然后清除数据库。我认为最好的方法是在同一台机器上进行dump/zip操作。我试图想出一种将转储流式传输到终端计算机的方式,但我想不出一种方法来做到这一点。我读过os.system已被弃用,所以我想我会给子进程一个镜头。尽管如此,我们也可以使用os.system。它足够简单。谢谢。 – Zobal

2

使用两个subprocess.Popen调用你的代码示例是正确的(虽然稍微提高,能),而这个:

...我读了沟通缓存内存中的数据

也是正确的 - 它将“通信命令”在subprocess.PIPE上产生的所有标准输出和标准错误输出读入到存储器中,但是在这里不是问题,因为你有这样的:

p1 = Popen(args, stdout=PIPE) 
P2 = Popen('gzip', stdin=p1.stdout, stdout=f) 
p2.communicate() 

你打电话communicate()p2,它的标准输出输出发送到f(打开的文件),其stderr输出,这可能是空的呢(没有发生错误) - 没有被发送到PIPE。因此,p2.communicate()最坏的情况是不得不读取并缓冲总共0字节的标准输出加零字节的标准错误。它实际上更聪明一些,注意到没有PIPE,所以它返回元组(None, None)

如果你打电话给p1.communicate(),那将是更大的问题(虽然在这种情况下,你再与p2,gzip的过程中战斗,从p1输出,这将是更糟糕)。但你不是; p1的输出流向p2,并且p2的输出流向文件。

由于没有p2的输出发送到PIPE,这里没有必要拨打p2.communicate():您可以简单地拨打p2.wait()。这更清楚地表明没有数据从p2(我认为这是对代码的小改进,尽管如果你决定要捕获p2的stderr毕竟,你必须改变它)。


编辑补充:在glglgl的答案,它创造P2后关闭p1的管p2是很重要的,否则会p2等待你的Python程序将数据发送到p2了。

+0

非常感谢。这是一个非常丰富的答案。 – Zobal

2

你是相当接近你想去的地方:

from subprocess import Popen, PIPE 

f = open(FILENAME, 'wb') 
args = ['mysqldump', '-u', 'UNAME', '-pPASSWORD', '--add-drop-database', '--databases', 'DB'] 

p1 = Popen(args, stdout=PIPE) 

到这里它是正确的。

p2 = Popen('gzip', stdin=p1.stdout, stdout=PIPE) 

这一个需要p1的输出和处理它。之后我们可以(也应该)立即p1.stdout.close()

现在我们可以从被读取,而在不使用临时文件p2.stdout,通过网络发送:

s = socket.create_connection(('remote_pc', port)) 
while True: 
    r = p2.stdout.read(65536) 
    if not r: break 
    s.send(r) 
+0

太棒了。我会给它一个镜头。 – Zobal

+1

你可能会想'sendall'。并且,关于从p1关闭输出管道的好处,否则p2不会完成... – torek

+0

@torek您对'sendall()'的描述是正确的... – glglgl