Python 使用 GNU Parallel 的管道
Python pipeline using GNU Parallel
我正在尝试在 Python 中围绕 GNU Parallel 编写一个包装器到 运行 并行命令,但似乎误解了 GNU Parallel 的工作方式,系统管道 and/or python 子进程管道。
本质上,我希望使用 GNU Parallel 来处理拆分输入文件,然后 运行 在多个主机上并行执行另一个命令。
我将来可以研究一些纯粹的 python 方法来做到这一点,但似乎应该可以使用 GNU Parallel 轻松实现。
t.py
#!/usr/bin/env python
import sys
print
print sys.stdin.read()
print
p.py
from subprocess import *
import os
from os.path import *
args = ['--block', '10', '--recstart', '">"', '--sshlogin', '3/:', '--pipe', './t.py']
infile = 'test.fa'
fh = open('test.fa','w')
fh.write('''>M02261:11:000000000-ADWJ7:1:1101:16207:1115 1:N:0:1
CAGCTACTCGGGGAATCCTTGTTGCTGAGCTCTTCCCTTTTCGCTCGCAGCTACTCGGGGAATCCTTGTTGCTGAGCTCTTCCCTTTTCGCTCGCAGCTACTCGGGGAATCCTTGTTGCTGAGCTCTTCCCTTTTCGCTCGCAGCTACTCGGGGAATCCTTGTTGCTGAGCTCTTCCCTTT
>M02261:11:000000000-ADWJ7:1:1101:21410:1136 1:N:0:1
ATAGTAGATAGGGACATAGGGAATCTCGTTAATCCATTCATGCGCGTCACTAATTAGATGACGAGGCATTTGGCTACCTTAAGAGAGTCATAGTTACTCCCGCCGTTTACC
>M02261:11:000000000-ADWJ7:1:1101:13828:1155 1:N:0:1
GGTTTAGAGTCTCTAGTCGATAGATCAATGTAGGTAAGGGAAGTCGGCAAATTAGATCCGTAACTTCGGGATAAGGATTGGCTCTGAAGGCTGGGATGACTCGGGCTCTGGTGCCTTCGCGGGTGCTTTGCCTCAACGCGCGCCGGCCGGCTCGGGTGGTTTGCGCCGCCTGTGGTCGCGTCGGCCGCTGCAGTCATCAATAAACAGCCAATTCAGAACTGGCACGGCTGAGGGAATCCGACGGTCTAATTAAAACAAAGCATTGTGATGGACTCCGCAGGTGTTGACACAATGTGATTTT
>M02261:11:000000000-ADWJ7:1:1101:14120:1159 1:N:0:1
GAGTAGCTGCGAGCGAAAAGGGAAGAGCTCAAGGGGAGGAAAAGAAACTAACAAGGATTCCCCGAGTAGCTGCGAGCGAAAAGGGAAGCGCCCAAGGGGGGCAACAGGAACTAACAAGAATTCGCCGACTAGCTGCGACCTGAAAAGGAAAAACCCAAGGGGAGGAAAAGAAACTAACAAGGATTCCCCGAGTAGCTGCGAGCAGAAAAGGAAAAGCACAAGAGGAGGAAACGACACTAATAAGACTTCCCATACAAGCGGCGAGCAAAACAGCACGAGCCCAACGGCGAGAAAAGCAAAA
>M02261:11:000000000-ADWJ7:1:1101:8638:1172 1:N:0:1
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
''')
fh.close()
# Call 1
Popen(['parallel']+args, stdin=open(infile,'rb',0), stdout=open('output','w')).wait()
# Call 2
_cat = Popen(['cat', infile], stdout=PIPE)
Popen(['parallel']+args, stdin=_cat.stdout, stdout=open('output2','w')).wait()
# Call 3
Popen('cat '+infile+' | parallel ' + ' '.join(args), shell=True, stdout=open('output3','w')).wait()
调用 1 和调用 2 产生相同的输出,而调用 3 产生我期望的输出,其中输入文件被拆分并且记录之间包含空行。
我比较好奇Call 1,2和Call 3有什么区别
TL;DR 当 shell=False
.
时不要引用 ">"
如果您使用 shell=True
,您可以使用 shell 的所有功能,例如 globbing、I/O 重定向等。您需要引用任何需要引用的内容逃出shell。您可以将整个命令行作为单个字符串传递,shell 将对其进行解析。
unsafe = subprocess.Popen('echo `date` "my files" * >output', shell=True)
使用 shell=False
,您在幕后没有 "secret" 副作用,并且 shell 的 none 设施可供您使用。因此,您需要在 Python 端处理 globbing、重定向等。在 plus 帐户上,您节省了一个(可能很重要的)额外过程,您有更多的控制权,并且您不需要(而且确实不能)引用涉及 shell 时必须引用的内容。综上所述,这样也比较安全,因为你可以一目了然地看到你在做什么。
cmd = ['echo']
cmd.append(datestamp())
cmd.append['my files'] # notice absence of shell quotes around string
cmd.extend(glob('*'))
safer = subprocess.Popen(cmd, shell=False, stdout=open('output', 'w+'))
(这仍然略有不同,因为对于现代 shells,echo
是内置的,而现在,我们将执行外部实用程序 /bin/echo
或任何带有它的可执行文件名字在你的 PATH
中排在第一位。)
现在,回到您的示例,您的 args
中的问题是您引用文字 ">"
作为记录分隔符。当涉及到 shell 时,不带引号的右折号会调用重定向,因此要将其指定为字符串,必须对其进行转义或引用;但是当图片中没有 shell 时,没有任何东西可以处理(或需要)这些引号,因此要传递文字 >
参数,只需按字面意思传递即可。
除此之外,您的第 1 号电话绝对是正确的选择。 (尽管我不完全相信为在 Perl 中实现的 shell 命令编写 Python 包装器是明智的。我怀疑直接在 Python 中处理一堆并行子进程会不会更复杂。)
我正在尝试在 Python 中围绕 GNU Parallel 编写一个包装器到 运行 并行命令,但似乎误解了 GNU Parallel 的工作方式,系统管道 and/or python 子进程管道。
本质上,我希望使用 GNU Parallel 来处理拆分输入文件,然后 运行 在多个主机上并行执行另一个命令。
我将来可以研究一些纯粹的 python 方法来做到这一点,但似乎应该可以使用 GNU Parallel 轻松实现。
t.py
#!/usr/bin/env python
import sys
print
print sys.stdin.read()
print
p.py
from subprocess import *
import os
from os.path import *
args = ['--block', '10', '--recstart', '">"', '--sshlogin', '3/:', '--pipe', './t.py']
infile = 'test.fa'
fh = open('test.fa','w')
fh.write('''>M02261:11:000000000-ADWJ7:1:1101:16207:1115 1:N:0:1
CAGCTACTCGGGGAATCCTTGTTGCTGAGCTCTTCCCTTTTCGCTCGCAGCTACTCGGGGAATCCTTGTTGCTGAGCTCTTCCCTTTTCGCTCGCAGCTACTCGGGGAATCCTTGTTGCTGAGCTCTTCCCTTTTCGCTCGCAGCTACTCGGGGAATCCTTGTTGCTGAGCTCTTCCCTTT
>M02261:11:000000000-ADWJ7:1:1101:21410:1136 1:N:0:1
ATAGTAGATAGGGACATAGGGAATCTCGTTAATCCATTCATGCGCGTCACTAATTAGATGACGAGGCATTTGGCTACCTTAAGAGAGTCATAGTTACTCCCGCCGTTTACC
>M02261:11:000000000-ADWJ7:1:1101:13828:1155 1:N:0:1
GGTTTAGAGTCTCTAGTCGATAGATCAATGTAGGTAAGGGAAGTCGGCAAATTAGATCCGTAACTTCGGGATAAGGATTGGCTCTGAAGGCTGGGATGACTCGGGCTCTGGTGCCTTCGCGGGTGCTTTGCCTCAACGCGCGCCGGCCGGCTCGGGTGGTTTGCGCCGCCTGTGGTCGCGTCGGCCGCTGCAGTCATCAATAAACAGCCAATTCAGAACTGGCACGGCTGAGGGAATCCGACGGTCTAATTAAAACAAAGCATTGTGATGGACTCCGCAGGTGTTGACACAATGTGATTTT
>M02261:11:000000000-ADWJ7:1:1101:14120:1159 1:N:0:1
GAGTAGCTGCGAGCGAAAAGGGAAGAGCTCAAGGGGAGGAAAAGAAACTAACAAGGATTCCCCGAGTAGCTGCGAGCGAAAAGGGAAGCGCCCAAGGGGGGCAACAGGAACTAACAAGAATTCGCCGACTAGCTGCGACCTGAAAAGGAAAAACCCAAGGGGAGGAAAAGAAACTAACAAGGATTCCCCGAGTAGCTGCGAGCAGAAAAGGAAAAGCACAAGAGGAGGAAACGACACTAATAAGACTTCCCATACAAGCGGCGAGCAAAACAGCACGAGCCCAACGGCGAGAAAAGCAAAA
>M02261:11:000000000-ADWJ7:1:1101:8638:1172 1:N:0:1
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
''')
fh.close()
# Call 1
Popen(['parallel']+args, stdin=open(infile,'rb',0), stdout=open('output','w')).wait()
# Call 2
_cat = Popen(['cat', infile], stdout=PIPE)
Popen(['parallel']+args, stdin=_cat.stdout, stdout=open('output2','w')).wait()
# Call 3
Popen('cat '+infile+' | parallel ' + ' '.join(args), shell=True, stdout=open('output3','w')).wait()
调用 1 和调用 2 产生相同的输出,而调用 3 产生我期望的输出,其中输入文件被拆分并且记录之间包含空行。
我比较好奇Call 1,2和Call 3有什么区别
TL;DR 当 shell=False
.
">"
如果您使用 shell=True
,您可以使用 shell 的所有功能,例如 globbing、I/O 重定向等。您需要引用任何需要引用的内容逃出shell。您可以将整个命令行作为单个字符串传递,shell 将对其进行解析。
unsafe = subprocess.Popen('echo `date` "my files" * >output', shell=True)
使用 shell=False
,您在幕后没有 "secret" 副作用,并且 shell 的 none 设施可供您使用。因此,您需要在 Python 端处理 globbing、重定向等。在 plus 帐户上,您节省了一个(可能很重要的)额外过程,您有更多的控制权,并且您不需要(而且确实不能)引用涉及 shell 时必须引用的内容。综上所述,这样也比较安全,因为你可以一目了然地看到你在做什么。
cmd = ['echo']
cmd.append(datestamp())
cmd.append['my files'] # notice absence of shell quotes around string
cmd.extend(glob('*'))
safer = subprocess.Popen(cmd, shell=False, stdout=open('output', 'w+'))
(这仍然略有不同,因为对于现代 shells,echo
是内置的,而现在,我们将执行外部实用程序 /bin/echo
或任何带有它的可执行文件名字在你的 PATH
中排在第一位。)
现在,回到您的示例,您的 args
中的问题是您引用文字 ">"
作为记录分隔符。当涉及到 shell 时,不带引号的右折号会调用重定向,因此要将其指定为字符串,必须对其进行转义或引用;但是当图片中没有 shell 时,没有任何东西可以处理(或需要)这些引号,因此要传递文字 >
参数,只需按字面意思传递即可。
除此之外,您的第 1 号电话绝对是正确的选择。 (尽管我不完全相信为在 Perl 中实现的 shell 命令编写 Python 包装器是明智的。我怀疑直接在 Python 中处理一堆并行子进程会不会更复杂。)