通过python并行运算cmd命令(以dyna为例)

通过python并行运算cmd命令(以dyna为例)

一、基础知识

1.1 dyna的cmd命令方式

若dyna求解器的路径为D:\Program Files\lsdyna\program\ls-dyna_smp_d_R11_1_0_winx64_ifort160.exe,需要执行的k文件路径为D:\ProgramData\lsdyna\DOEv4.X\DOEv4.3\job.k,则通过cmd可调用 dyna求解器对k文件进行计算,cmd窗口中输入代码为

其中,NCPU=8 含义为8核SMP计算。

1.2 python执行cmd命令

python中,可以通过os库中的os.system(command)来执行cmd命令,如python通过cmd设置定时关机的代码可表示为

1.3 python的并行机制

python的threading 模块提供了多线程运行方式,具体细节可参考 Python threading实现多线程 基础篇 - 知乎 (zhihu.com),总体而言,实现多线程运行有两种方式:

  1. 创建Thread 的实例,传给它一个可调用对象(函数或者类的实例方法)。
  2. 派生Thread 的子类,并创建子类的实例。

方式一的案例为:

方式二的案例为:

两种方式的结果为:

---开始--- 一 时间 Fri Nov 29 11:34:31 2019
---开始--- 二 时间 Fri Nov 29 11:34:31 2019
***结束*** 一 时间 Fri Nov 29 11:34:32 2019
***结束*** 二 时间 Fri Nov 29 11:34:33 2019

二、 python并行运算

2.1 文件说明

任务目标为执行多个k文件,每个k文件位于一个独立的文件夹下,所有文件夹存放在同一个总体文件夹之中,文件组织如下。

文件夹目录
单个文件夹内

2.2 整体思路

程序的输入为总体文件夹的路径、进程数量NProcessor、单进程调用核的数量NCPU、输出为执行有限元仿真的cmd代码及在cmd中的并行执行,并辅以日志和实时显示的功能。步骤如下:

  1. 定义类的主体,确定dyna路径,输入NCPU和NProcessor来初始化类;
  2. 搜索总体文件夹下的子文件夹,记录在类变量KfileDirs中;
  3. 将KfileDirs视为队列,实施并行计算;
    1. 每次从KfileDirs中取出一个KfileDir,将它作为参数调用pulltask函数来启用进程(根据k文件路径调用cmd执行,并返回进程);
    2. 动态展示当前各个进程的状态和信息;
    3. 只要KfileDirs未完全遍历 或 全部进程均空闲,就继续执行;

总体代码如下:

from threading import Thread
import os
import time
import logging
from utilis.logger import setlogger
from utilis.ParrellelRunLib import watchdog_check,pull_task,check_single_thread
from datetime import datetime
import threading
import time


class Parel_Runer(object):
    lsdyna_dir = "D:\\Program Files\\lsdyna\\program\\ls-dyna_smp_d_R11_1_0_winx64_ifort160.exe"
    Kfile_name = 'job.k'

    def __init__(self,NCPU = 6, NProcessor = 7):
        self.NCPU = NCPU
        self.thread_register = [None for i in range(NProcessor)]

    def run_in_dir(self,dir): #获取需要执行的k文件路径列表,并调用函数执行
        self.dir = dir
        setlogger(os.path.join(self.dir, 'training-%s.log' % datetime.strftime(datetime.now(), '%m%d-%H%M%S')))

        #获取需要执行的k文件路径列表
        self.KfileDirs = []
        subdirs = next(os.walk(self.dir))[1]
        for subdir in subdirs:
            if 'condition' in subdir:
                self.KfileDirs.append(os.path.join(dir,subdir))
        
        #记录
        for KfileDir in self.KfileDirs:
            commandline = '"%s" I=%s NCPU=%d' % (self.lsdyna_dir, os.path.join(KfileDir, self.Kfile_name), self.NCPU)
            logging.info('dir:\t' + KfileDir)
            logging.info('command:\t' + commandline + '\n \n')
        logging.info('--' * 20)

        #执行
        self.run_actually()

    def run_actually(self):
        start = time.time()
        # 循环执行条件 :KfileDirs不为空或 线程不全为空
        while len(self.KfileDirs) > 0 or not register_is_free(self.thread_register):
            response = watchdog_check(self.thread_register)
            if response != None:  # 检查是否有空闲,空闲返回
                KfileDir= self.KfileDirs.pop(0)
                commandline = '"%s" I=%s NCPU=%d' % (self.lsdyna_dir, os.path.join(KfileDir, self.Kfile_name), self.NCPU)
                self.thread_register[response] = pull_task(commandline, KfileDir, "thread-%d" % (response + 1))
            time.sleep(2)
            # 动态刷新
            timeinfo = "<{:s}> processtime:{:6.2f}min |||||\n".format(datetime.strftime(datetime.now(), '%H:%M:%S'),
                                                                    (time.time() - start) / 60)
            showinfo = ["<thread-{:<2d} | mode: {:^9s} | running time:{:5.2f}min> | processdir: {:s}\n"
                            .format(i + 1, check_single_thread(item), 0 if item is None else item.runningtime() / 60,
                                    "None" if item is None else os.path.split(item.cal_dir)[-1])
                        for i, item in enumerate(self.thread_register)]
            print('\r', timeinfo, *showinfo, end='')

if __name__ == '__main__':
    runner = Parel_Runer()
    runner.run_in_dir(r'D:\ProgramData\lsdyna\Ex1-Model2\1_SimplifiedModel\5-generation\table_v2')

2.3 详解pull task函数

  1. CustomThread类,是threading.Thread的子类;
  2. pull_task函数,接受了K文件路径和计算结果放置路径,然后通过CustomThread唤起了进程执行execute_cmd_repeat函数并返回该进程变量;
  3. execute_cmd_repeat函数,目的为循环执行有限元。为防止有限元不收敛提前终止,因此通过该函数对生成文件d3plot的数量进行检查,如果生成d3plot的数量不达标且未达到重复上限,则清除生成的文件并再次执行有限元仿真;
  4. execute_cmd函数,单次执行有限元仿真。跟据生成文件夹更改执行路径,然后根据K文件路径执行有限元仿真;
  5. cal_d3plot_number函数:统计文件夹下d3plot文件的数量;
  6. clearfile函数:清除文件夹下k文件外的所有文件。
class CustomThread(threading.Thread):
    def __init__(self, *args,**kwargs):
        super().__init__(*args,**kwargs)
    def setdir(self,cal_dir):
        self.cal_dir = cal_dir
    def run(self):
        self.starttime = time.time()
        self._target(*self._args)

    def runningtime(self):
        try:
            return time.time() - self.starttime
        except:
            return 0

def pull_task(commandline,cal_dir=None,name = None):
    t = CustomThread(target=execute_cmd_repeat, args=(commandline,cal_dir), name= name)
    t.setdir(cal_dir)
    t.start()
    return t

def execute_cmd_repeat(command,cal_dir='./',repeat=2,d3plotfile_target=100):
     runtime = 0
     number = cal_d3plot_number(cal_dir)
     while (number < d3plotfile_target and runtime < repeat):
         clearfile(cal_dir)
         execute_cmd(command,cal_dir,runtime)
         number = cal_d3plot_number(cal_dir)
         runtime += 1



def execute_cmd(command,cal_dir='./',repeattime=0):
    log_info=['-----' * 10, "calculation start in %s:"%threading.current_thread().name,
              cal_dir,command,'\nrepeattime: %d\n'%repeattime,'-----' * 10]
    for item in log_info:
        logging.info(item)

    #获取当前路径
    os.chdir(cal_dir)
    os.system(command)

    log_info=['-----' * 10, "calculation finished in %s:"%threading.current_thread().name,
              cal_dir,command,'\nrepeattime: %d\n'%repeattime,'-----' * 10]
    for item in log_info:
        logging.info(item)


def cal_d3plot_number(cal_dir):
    files = next(os.walk(cal_dir))[2]
    count = 0
    for file in files:
        if 'd3plot' in file:
            count += 1
    return count

def clearfile(target_dir):
    files = next(os.walk(target_dir))[2]
    for file in files:
        if not file.endswith('.k'):
            os.remove(os.path.join(target_dir,file))

2.4 其他函数

  1. watchdog函数:检查线程列表中的线程是否有空闲,若有空闲,返回空闲的线程编号,否则返回None;
  2. register_is_free函数:检查线程列表是否全部空闲;
  3. check_single_thread函数:检查单个线程是否在运行;

2.5 运行时的情况

资讯网属猴取名起名大全帮朋友过生日续写作文qq签名爱情属鼠姓陈起名字外贸营销推广公司男孩起名何嘉吃鸡之无限升级系统女孩子起名字什么好听万宝缘珠宝给孩子起名字大全男孩2021建设模板网站方案周易起店铺名哈佛中国史读后感seo交流群周易八八六十四卦数字签名解决以下哪些问题白山黑水铸英魂观后感100字晋城门户网站建设个人简历网站的制作方法福州网络seo湘潭高端网站建设石家庄网站建设服务德阳网站seo用dw制作网站新网站推广案例seo工作安排尚书和周易房地产设计网站鬼故事红绳我就是这般女子剧情介绍金姓女起名字少年生前被连续抽血16次?多部门介入两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”淀粉肠小王子日销售额涨超10倍高中生被打伤下体休学 邯郸通报单亲妈妈陷入热恋 14岁儿子报警何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言张家界的山上“长”满了韩国人?男孩8年未见母亲被告知被遗忘中国拥有亿元资产的家庭达13.3万户19岁小伙救下5人后溺亡 多方发声315晚会后胖东来又人满为患了张立群任西安交通大学校长“重生之我在北大当嫡校长”男子被猫抓伤后确诊“猫抓病”测试车高速逃费 小米:已补缴周杰伦一审败诉网易网友洛杉矶偶遇贾玲今日春分倪萍分享减重40斤方法七年后宇文玥被薅头发捞上岸许家印被限制高消费萧美琴窜访捷克 外交部回应联合利华开始重组专访95后高颜值猪保姆胖东来员工每周单休无小长假男子被流浪猫绊倒 投喂者赔24万小米汽车超级工厂正式揭幕黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发当地回应沈阳致3死车祸车主疑毒驾恒大被罚41.75亿到底怎么缴妈妈回应孩子在校撞护栏坠楼外国人感慨凌晨的中国很安全杨倩无缘巴黎奥运校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变王树国卸任西安交大校长 师生送别手机成瘾是影响睡眠质量重要因素国产伟哥去年销售近13亿阿根廷将发行1万与2万面值的纸币兔狲“狲大娘”因病死亡遭遇山火的松茸之乡“开封王婆”爆火:促成四五十对奥巴马现身唐宁街 黑色着装引猜测考生莫言也上北大硕士复试名单了德国打算提及普京时仅用姓名天水麻辣烫把捣辣椒大爷累坏了

资讯网 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化