两种策略

第一策略:简单并行(简单命令)

如果我们只是希望批量并行,可以尝试以下代码,这里以批量进行bwa 比对为例子:

  1. dir=~/pipeline/wes_analysis/bilibili_1/project/2.clean_fq/
  2. cat name | while read id
  3. do
  4. 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 &
  5. done
  6. bash test_parallel.sh

第二策略:记录时间和判断完成文件(复杂命令)

如果我们希望像https://www.yuque.com/mugpeng/sequence/rnc3kw (你可以阅读这篇文章,了解一些这样运行命令的好处)一样,批量的生成文件,每个文件都包含以下结构:

  1. if [ ! -f ./status/ok.${id}.status ]
  2. then
  3. echo "start for ${id}" `date`
  4. nohup expr 1 + 1 > {id}.log 2>&1 &
  5. if [ $? -eq 0 ]
  6. then
  7. touch ./status/ok.${id}.status
  8. fi
  9. echo "end for ${id}" `date`
  10. fi
  11. done > batch_${id}.sh

我们可以分别创建两个文件夹,分别用来保存每个文件命令运行的log 文件和时间文件。接着批量运行后台运行它们:

  1. cat config | while read id
  2. do
  3. nohup bash ./batch_sh/batch_${id}.sh > ./batch_time_log/${id}_time.log 2>&1 &
  4. done

究竟如何实现生成这样的批量运行脚本batch_${id}.sh 呢?

我们可以利用打印,把它们给批量打印出来:

  1. dir=~/urdir/
  2. cat $work_dr/name.txt | while read id
  3. do
  4. (echo "echo "start operation ${id}"" '$(date)'
  5. echo "expr 1 + 1 > ./batch_log/${id}.log 2>&1 &"
  6. echo "echo "finish operation ${id}"" '$(date)') > ./batch_sh/batch_${id}.sh
  7. done

如果想还是文件判断内容,可以参考后面的总结部分。

第二策略分部总结

代码共分为四个部分。

我只是用两个fq 数做一个bwa 比对的范例。

第一个部分:准备阶段

准备阶段,准备配置文件,创建文件夹,用来存储批量脚本、批量日志、批量时间日志:

  1. $cat config
  2. ERR2497940
  3. ERR2497942
  4. $mkdir status bwa_log bwa_time_log bwa_sh
  5. $ls
  6. bwa_log bwa_sh bwa_time_log config status

第二个部分:批量打印脚本

  1. dir=~/pipeline/wes_analysis/bilibili_1/project/2.clean_fq/test
  2. cat $dir/config | while read id
  3. do
  4. (echo "if [ ! -f ./status/ok.${id}.status ]
  5. then echo "start operation ${id}"" '$(date)'
  6. 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"
  7. echo "if [ \$? -eq 0 ]; then touch ./status/ok.${id}.status; fi
  8. fi
  9. echo "end for ${id}"" '$(date)') > ./bwa_sh/bwa_${id}.sh
  10. done
  11. bash bwa_script.sh &

我们可以看一下批量生成的一个文件:

  1. $cd bwa_sh/
  2. $ls
  3. bwa_ERR2497940.sh bwa_ERR2497942.sh
  4. $cat bwa_ERR2497940.sh
  5. if [ ! -f ./status/ok.ERR2497940.status ]
  6. then echo start operation ERR2497940 $(date)
  7. 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
  8. if [ $? -eq 0 ]; then touch ./status/ok.ERR2497940.status; fi
  9. fi
  10. echo end for ERR2497940 $(date)

第三个部分:批量运行脚本

记得在配置的环境中运行命令哦:

  1. conda activate wes_py3

运行命令:

  1. cat ./config | while read id
  2. do
  3. nohup bash ./bwa_sh/bwa_${id}.sh 1>./bwa_time_log/${id}_time.log 2>&1 &
  4. done

我们可以通过top 查看一下指令是否成功运行:

  1. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  2. 194890 yzpen 20 0 6152740 5.7g 2976 S 427.8 1.5 1:37.57 bwa
  3. 194892 yzpen 20 0 6162224 5.7g 2940 S 422.2 1.5 1:37.44 bwa

成功的并行运行了~

第四个部分:等待结果

最终,除了命令(我的是比对命令生成的sam 文件)生成的文件外,我们一共创建了以下文件:

  1. $tree
  2. ├── bwa_log
  3. ├── ERR2497940.log
  4. └── ERR2497942.log
  5. ├── bwa_script.sh
  6. ├── bwa_sh
  7. ├── bwa_ERR2497940.sh
  8. └── bwa_ERR2497942.sh
  9. ├── bwa_time_log
  10. ├── ERR2497940_time.log
  11. └── ERR2497942_time.log
  12. ├── config
  13. └── status
  14. ├── ok.ERR2497940.status
  15. └── ok.ERR2497942.status

并行虽好,可不要贪杯哦,内存,线程,这些资源都是有上限的,因此合理的使用并行,才可以达到事半功倍的效果!

老的回忆

ps:这是我之前写的,核心思路还是将需要执行的代码拆分成多个文件,比较丑,仅供自己欣赏~

我们平时提交后台的都是循环执行的,比如下面这行bwa 的代码,就是对config 中的数据循环进行bwa,先对SRR12692093 比对,再是SRR12692098,SRR12692099:

  1. $ cat ~/project/atac_try/pipeline/config
  2. SRR12692093
  3. SRR12692098
  4. SRR12692099
  5. cat ../config | while read id
  6. do
  7. 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 -
  8. done
  9. # 后台运行
  10. 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)

直接后台运行全部的脚本便达到批量的效果啦~

  • 结束语

并行虽好,可不要贪杯哦,内存,线程,这些资源都是有上限的,因此合理的使用并行,才可以达到事半功倍的效果!