两种策略
第一策略:简单并行(简单命令)
如果我们只是希望批量并行,可以尝试以下代码,这里以批量进行bwa 比对为例子:
dir=~/pipeline/wes_analysis/bilibili_1/project/2.clean_fq/
cat name | while read id
do
nohup bwa mem -M -t 4 -R "@RG\tID:${id}\tSM:${id}\tLB:WXS\tPL:Illumina" /home/yzpen/pipeline/wes_analysis/bilibili_1/data/bwa/index/hg38 $dir/${id}_1_val_1.fq.gz $dir/${id}_2_val_2.fq.gz 1>./${id}.log 2>&1 &
done
bash test_parallel.sh
第二策略:记录时间和判断完成文件(复杂命令)
如果我们希望像https://www.yuque.com/mugpeng/sequence/rnc3kw (你可以阅读这篇文章,了解一些这样运行命令的好处)一样,批量的生成文件,每个文件都包含以下结构:
if [ ! -f ./status/ok.${id}.status ]
then
echo "start for ${id}" `date`
nohup expr 1 + 1 > {id}.log 2>&1 &
if [ $? -eq 0 ]
then
touch ./status/ok.${id}.status
fi
echo "end for ${id}" `date`
fi
done > batch_${id}.sh
我们可以分别创建两个文件夹,分别用来保存每个文件命令运行的log 文件和时间文件。接着批量运行后台运行它们:
cat config | while read id
do
nohup bash ./batch_sh/batch_${id}.sh > ./batch_time_log/${id}_time.log 2>&1 &
done
究竟如何实现生成这样的批量运行脚本batch_${id}.sh 呢?
我们可以利用打印,把它们给批量打印出来:
dir=~/urdir/
cat $work_dr/name.txt | while read id
do
(echo "echo "start operation ${id}"" '$(date)'
echo "expr 1 + 1 > ./batch_log/${id}.log 2>&1 &"
echo "echo "finish operation ${id}"" '$(date)') > ./batch_sh/batch_${id}.sh
done
如果想还是文件判断内容,可以参考后面的总结部分。
第二策略分部总结
代码共分为四个部分。
我只是用两个fq 数做一个bwa 比对的范例。
第一个部分:准备阶段
准备阶段,准备配置文件,创建文件夹,用来存储批量脚本、批量日志、批量时间日志:
$cat config
ERR2497940
ERR2497942
$mkdir status bwa_log bwa_time_log bwa_sh
$ls
bwa_log bwa_sh bwa_time_log config status
第二个部分:批量打印脚本
dir=~/pipeline/wes_analysis/bilibili_1/project/2.clean_fq/test
cat $dir/config | while read id
do
(echo "if [ ! -f ./status/ok.${id}.status ]
then echo "start operation ${id}"" '$(date)'
echo "bwa mem -M -t 4 -R \"@RG\tID:${id}\tSM:${id}\tLB:WXS\tPL:Illumina\" /home/yzpen/pipeline/wes_analysis/bilibili_1/data/bwa/index/hg38 $dir/../${id}_1_val_1.fq.gz $dir/../${id}_2_val_2.fq.gz > ./bwa_log/${id}.log 2>&1"
echo "if [ \$? -eq 0 ]; then touch ./status/ok.${id}.status; fi
fi
echo "end for ${id}"" '$(date)') > ./bwa_sh/bwa_${id}.sh
done
bash bwa_script.sh &
我们可以看一下批量生成的一个文件:
$cd bwa_sh/
$ls
bwa_ERR2497940.sh bwa_ERR2497942.sh
$cat bwa_ERR2497940.sh
if [ ! -f ./status/ok.ERR2497940.status ]
then echo start operation ERR2497940 $(date)
bwa mem -M -t 4 -R "@RG\tID:ERR2497940\tSM:ERR2497940\tLB:WXS\tPL:Illumina" /home/yzpen/pipeline/wes_analysis/bilibili_1/data/bwa/index/hg38 /home/yzpen/pipeline/wes_analysis/bilibili_1/project/2.clean_fq/test/../ERR2497940_1_val_1.fq.gz /home/yzpen/pipeline/wes_analysis/bilibili_1/project/2.clean_fq/test/../ERR2497940_2_val_2.fq.gz > ./bwa_log/ERR2497940.log 2>&1
if [ $? -eq 0 ]; then touch ./status/ok.ERR2497940.status; fi
fi
echo end for ERR2497940 $(date)
第三个部分:批量运行脚本
记得在配置的环境中运行命令哦:
conda activate wes_py3
运行命令:
cat ./config | while read id
do
nohup bash ./bwa_sh/bwa_${id}.sh 1>./bwa_time_log/${id}_time.log 2>&1 &
done
我们可以通过top 查看一下指令是否成功运行:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
194890 yzpen 20 0 6152740 5.7g 2976 S 427.8 1.5 1:37.57 bwa
194892 yzpen 20 0 6162224 5.7g 2940 S 422.2 1.5 1:37.44 bwa
成功的并行运行了~
第四个部分:等待结果
最终,除了命令(我的是比对命令生成的sam 文件)生成的文件外,我们一共创建了以下文件:
$tree
├── bwa_log
│ ├── ERR2497940.log
│ └── ERR2497942.log
├── bwa_script.sh
├── bwa_sh
│ ├── bwa_ERR2497940.sh
│ └── bwa_ERR2497942.sh
├── bwa_time_log
│ ├── ERR2497940_time.log
│ └── ERR2497942_time.log
├── config
└── status
├── ok.ERR2497940.status
└── ok.ERR2497942.status
并行虽好,可不要贪杯哦,内存,线程,这些资源都是有上限的,因此合理的使用并行,才可以达到事半功倍的效果!
老的回忆
ps:这是我之前写的,核心思路还是将需要执行的代码拆分成多个文件,比较丑,仅供自己欣赏~
我们平时提交后台的都是循环执行的,比如下面这行bwa 的代码,就是对config 中的数据循环进行bwa,先对SRR12692093 比对,再是SRR12692098,SRR12692099:
$ cat ~/project/atac_try/pipeline/config
SRR12692093
SRR12692098
SRR12692099
cat ../config | while read id
do
bwa mem -M -t 4 -R "@RG\tID:${id}\tSM:${id}\tLB:WXS\tPL:Illumina" /home/yzpen/pipeline/wes_analysis/bilibili_1/data/bwa/index/hg38 ${id}_1_val_1.fq.gz ${id}_2_val_2.fq.gz | samtools sort -@ 4 -m 4G -o ../4.align/${id}.bam -
done
# 后台运行
nohup sh bwa.sh > ../../log/bwa.log 2>&1 &
那什么是并行运行呢?
简单来说,比如我在使用bwa 比对的时候,你在使用gatk 做变异分析,那同时运行的这两个程序就是并行的,计算机会分配不同的资源去执行任务。
因此,如果我们需要短时间内快速的进行某些操作,比如变异检测等这些费时的步骤,那么可以尝试并行运行你的代码,即同时执行多个命令。
从操作角度来看,你可以手动运行你的命令,nohup xx_1 nohup xx_2…这太麻烦了~
因此,你也可以将需要执行的命令使用循环echo 出一个新的脚本,每个新的脚本对应一组数据运行的代码,批量执行这些脚本就可以达到并行的目的:
ps:能力有限,代码比较丑,见谅,QAQ
reference=/data/software_ref/gatk/gatk-bundle/Homo_sapiens_assembly38.fasta
rmdup_bam_dr=~/project/001_BRCA-KI/wes/2.align/rmdup
work_dr=~/project/001_BRCA-KI/wes
cat $work_dr/config_pair_8 | while read id
do
arr=($id)
normal_bam=${arr[0]}
tumor_bam=${arr[1]}
(echo "echo "start varscan $tumor_bam"" '$(date)'
echo "normal_pileup=\"samtools mpileup -q 1 -f $reference ${rmdup_bam_dr}/${normal_bam}_rmdup.bam\"
tumor_pileup=\"samtools mpileup -q 1 -f $reference ${rmdup_bam_dr}/${tumor_bam}_rmdup.bam\""
echo 'varscan somatic <($normal_pileup) <($tumor_pileup)' "${tumor_bam}_varscan --output-vcf"
echo "varscan processSomatic ${tumor_bam}_varscan.snp.vcf
varscan processSomatic ${tumor_bam}_varscan.indel.vcf"
echo "echo "finish varscan $tumor_bam"" '$(date)') > ${tumor_bam}_varscan.sh
done
执行完了,目录中就会出现多个脚本:
$ ls *WGC*.sh
WGC078975U_varscan.sh WGC101030U_varscan.sh WGC101045U_varscan.sh
WGC078976U_varscan.sh WGC101032U_varscan.sh
每个脚本对应一组数据的命令,我这里是varscan 的变异检测:
$ cat WGC101030U_varscan.sh
echo start varscan WGC101030U $(date)
normal_pileup="samtools mpileup -q 1 -f /data/software_ref/gatk/gatk-bundle/Homo_sapiens_assembly38.fasta /home/yzpen/project/001_BRCA-KI/wes/2.align/rmdup/WGC101031U_rmdup.bam"
tumor_pileup="samtools mpileup -q 1 -f /data/software_ref/gatk/gatk-bundle/Homo_sapiens_assembly38.fasta /home/yzpen/project/001_BRCA-KI/wes/2.align/rmdup/WGC101030U_rmdup.bam"
varscan somatic <($normal_pileup) <($tumor_pileup) WGC101030U_varscan --output-vcf
varscan processSomatic WGC101030U_varscan.snp.vcf
varscan processSomatic WGC101030U_varscan.indel.vcf
echo finish varscan WGC101030U $(date)
直接后台运行全部的脚本便达到批量的效果啦~
- 结束语
并行虽好,可不要贪杯哦,内存,线程,这些资源都是有上限的,因此合理的使用并行,才可以达到事半功倍的效果!