python子进程和mysqldump
我知道以前有人问过这个问题的一部分,但我有一些相关的问题 我正试图执行python子进程和mysqldump,python,subprocess,mysqldump,Python,Subprocess,Mysqldump,我知道以前有人问过这个问题的一部分,但我有一些相关的问题 我正试图执行 mysqldump -u uname -ppassword --add-drop-database --databases databaseName | gzip > fileName 我可能会转储一个非常大的(200GB?)db。这本身就是一件愚蠢的事情吗?然后我想通过网络发送压缩文件进行存储,删除本地转储,并清除几个表 无论如何,我是这样使用子流程的,因为似乎没有一种方法可以在不将子流程视为表名的情况下执行整个原
mysqldump -u uname -ppassword --add-drop-database --databases databaseName | gzip > fileName
我可能会转储一个非常大的(200GB?)db。这本身就是一件愚蠢的事情吗?然后我想通过网络发送压缩文件进行存储,删除本地转储,并清除几个表
无论如何,我是这样使用子流程的,因为似乎没有一种方法可以在不将子流程视为表名的情况下执行整个原始调用
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()
但后来我读到,Communication将数据缓存在内存中,这对我来说不起作用。这是真的吗
我现在要做的是:
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的输出通过管道传输到套接字,并通过网络启动它,在它到达时保存它,而不是发送压缩文件
谢谢 是的,数据缓冲在内存中: “注意,读取的数据缓冲在内存中,因此不要使用此方法 如果数据大小较大或不受限制。“- 不幸的是,目前无法异步使用Popen: 您可以手动执行这些操作,而不是在python中执行所有操作
os.system("mysqldump -u uname -ppassword --add-drop-database --databases databaseName | gzip > fileName
))
当然,使用string.format
进行适当的字符串替换;否则会给计算机带来不必要的压力,尤其是试图通过管道与200gb的数据通信
你能详细说明一下你想做什么吗?现在听起来你好像在同一台电脑上进行转储和压缩
是的,你可以通过网络传输一个文件。我不知道你是否想直接传输mysql的输出-在考虑之前,你可能想看看你的网络功能
狂欢节: ^您也可以将它放在crontab中,并让它每隔一段时间运行:)您不需要communicate()。如果您想将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()
您使用两个
subprocess.Popen
调用的示例代码是正确的(尽管略有改进),如下所示:
…我读取的数据会将数据缓存在内存中
也是正确的,它会将“通信命令”在子流程管道上产生的所有标准输出和标准错误输出读入内存,但这里没有问题,因为您有以下问题:
p1 = Popen(args, stdout=PIPE)
P2 = Popen('gzip', stdin=p1.stdout, stdout=f)
p2.communicate()
您正在p2
上调用communicate()
,它的标准输出被发送到f
(一个打开的文件),并且它的标准输出可能是空的(不会发生错误)-不会被发送到管道。因此,p2.communicate()
在最坏的情况下必须读取和缓冲总计为零字节的stdout加上零字节的stderr。它实际上更聪明一些,注意到没有管道,所以它返回元组(无,无)
如果您要调用p1.communicate()
,这将是一个更大的问题(尽管在这种情况下,您将使用p2
,gzip进程来处理p1
的输出,这将更糟)。但您不是;p1
的输出流到p2
,而p2
的输出流到文件
由于没有一个p2
的输出被发送到管道
,因此无需在此处调用p2.communicate()
:您只需调用p2.wait()
。这就更清楚了,没有数据从p2
返回(我想说这是对代码的一个小小改进,不过如果您决定捕获p2
的stderr,您必须将其更改回来)
编辑以添加:正如GLGL的回答一样,在创建p2之后关闭p1
到p2
的管道非常重要,否则p2
也将等待Python进程将数据发送到p2
。您已经非常接近您想要的位置:
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)
情况是这样的:我正在将数据收集到一个系统上的数据库中。当磁盘达到某个阈值时,我想将压缩转储移动到另一个系统,并清除数据库。我认为最好的方法是在同一台机器上转储/zip。我试图想出一种将转储流到最终计算机的方法,但我想不出一个way这样做。我已经读到os.system不推荐使用,所以我想我应该尝试一下子流程。不过也可以尝试一下us os.system。这很简单。谢谢。@glglgl在glglgl;d中没有不推荐使用。另外,Zobal您可能想尝试一个bash脚本,而不是python脚本。如果这些脚本在同一台计算机上,您不需要使用pipe的n必要的。这些用于进程间信令,更多的用于传输大量数据。谢谢。这就是我要找的!太棒了。我会试一试。您可能需要sendall
。另外,关闭p1的输出管道很好,否则p2将无法完成…相关:
s = socket.create_connection(('remote_pc', port))
while True:
r = p2.stdout.read(65536)
if not r: break
s.send(r)