pesticide_ccnu 发表于 2016-9-2 20:54:06

基于python和bash的多线程任务框架 不要让cpu闲着了

本帖最后由 pesticide_ccnu 于 2016-9-2 21:36 编辑

      在分子模拟漫漫长路中,你有没有遇到这样的情况:我有一台多核机器,也有超算账号,有几百上千乃至几十万的分子要对接,假如我想把cpu全部用起来,那该怎么办呢?一个简单的思路是开多个进程,简单来讲,我可以把分子均分为几个文件夹,写个脚本投递N次,最后再写脚本收集数据。此法简单直接,但是分文件夹使得数据变零散,比较烦人,
另外多个进程的话,相互之间很难通信,可能一个进程很快跑完就造成了cpu的浪费。

       下面提供两个多线程框架,可以用于几乎所有的分子模拟软件(已经有并行功能的程序只要不是把cpu吃满也可以应用),一个bash的一个python的,各有千秋。

       bash在linux下几乎无所不能,其优势是能很好的与机器通信以获取任务的相关信息,有些功能是其他语言或者工具无法完成的,调用起计算程序特别方便(所以一个看似麻烦
的功能也许只需要几句话,比如诸多配体对接到同一个蛋白中),缺点在于数学计算,矩阵操作写起脚本来麻烦且跑起来慢。python给我的感觉是灵活,对于有一定复杂性的任务,
因为其强大的数学计算,向量和矩阵操作,脚本写起来快,运行也快,诸多实用模块也能满足很多功能。

       扯远了点。。。下面回到主题。这里提供了bash和python两种多线程解决方案,适合对于这两种语言有一定了解的同学,没有提供测试文件,因为主要是介绍框架的。            


       下面是bash的多线程框架,用ad实现多个复合物的redock(为了易于理解,简化了脚本,实际上完全可以实现自动redock,即从实验复合物获得对接预测复合物)。
可参考http://www.cnblogs.com/xuxm2007/p/5820633.html了解更多。

#! /bin/bash
##########################################################################################################
#part1:defile your job(第一部分,定义单核任务,需要根据你的实用任务改动)
date >>time
Nproc=40                                    #prcocess used here (要用的线程数)
ls *ligand.mol2 >list                  #list of jobs (所有的任务放到一个list里面)
Njob=$(echo $(cat list|wc -l)+1|bc)         #total jobs+1 (统计总任务数目)
function jobrun                                       #define your job (定义一个函数任务)
{
j=$(cat list|sed -n "$1"p|cut -c 1-4)         #$1 is a parameter for jobid ($1作为函数输入 即任务号 这里首先要找到任务号对应的分子)
prepare_dpf42.py -l $j"_ligand.pdbqt" -r $j"_receptor.pdbqt" -o tmp2 #(为了简单期间这里没有写如何计算格子 如何计算格点文件这里是从准备dpf文件开始)
autodock4 -p $j.dpf -l $j.dlg #(对接)
}
##############################################################################################################
#part2:mutiple process framwork (第二部分,多线程框架,可以不用懂不用改动)
PID=()                                 #PID is an array to store the pid of your job (PID 用于储存每个线程的pid)
for ((i=1;i<Njob;))
do
for((Ijob=0; Ijob<Nproc; Ijob++));
do
if [[ $i -ge $Njob ]]; #(如果任务都完成了就退出循环)
then
break;
fi
if [[ ! "${PID}" ]] || ! kill -0 ${PID} 2> /dev/null; then #(如果线程没有被占用)
echo start $i with $Ijob
jobrun $i $Ijob&      #(用Ijob线程执行任务i)
PID=$!         #(任务完成 释放线程Ijob)
i=$((i+1))
fi
done
##########################################################################################
wait #(等所有线程都空闲下来)
done
echo job finished!
date >>time      

下面是python版本 用于实现批量vina对接筛选。参考 http://blog.chinaunix.net/uid-26990529-id-3390814.html
#!/usr/bin/python
import re,os,multiprocessing
#part1:defile job                      (定义一个带参数的函数)
def f(ligand):
os.popen('prepare_ligand4.py -l '+ligand+'.mol2')
os.popen('vina --config '+ligand+' --log '+ligand+'.txt')
os.popen('rm '+ligand+'.mol2')

os.popen('cat /proc/cpuinfo | grep "processor" | wc -l > cpu') #读取cpu信息以统计cpu数目
fi=open('cpu').readlines()
a=int(fi.split())                                                                #a是cpu数目 也就是线程数目
#part2:mutiple process framwork (第二部分,多线程框架,可以不用懂不用改动)
if __name__ == "__main__":
pool=multiprocessing.Pool(processes=a) #开a个线程
lig=os.listdir(pathfirst+'//database') #获取分子列表
for i in lig:
    p,q=os.path.splitext(i)
    pool.apply_async(f,(p,))                                                          #调用函数,以分子名作为参数输入函数f
    pool.close()
    pool.join()

       可以看到,两种语言基本都包含两个部分,第一个部分要定义一个函数,将模拟的命令放进去,一般需要一些参数(这里是分子序号或者分子名)作为输入。
根据模拟类型不通,内容也不同。第二部分是多线程框架,一般不需要改动。
       两种方法各有千秋,bash的方法多线程框架部分相对复杂,但是定义起函数非常方便。python方法因为有专门的模块,所以多线程功能更加灵活强大。另有
perl版本的因为我自己也看不懂,故此处就不列举了。






xufund 发表于 2016-9-2 21:23:30

牛人啊!俺好好学习一下

璐璐 发表于 2016-9-3 10:58:31

厉害厉害:handshake

川大-灰太狼 发表于 2016-9-4 20:54:44

哈哈,原创好文!绝对python学习好范本。

李云Echo 发表于 2019-10-29 13:36:25

学习了!!
感谢
页: [1]
查看完整版本: 基于python和bash的多线程任务框架 不要让cpu闲着了