python,标准输出重定向,为进程设置工作目录,python启动c++可执行程序Popen,dict和json转换,python读取配置文件,python类转json(dict), IntEnum

1,工程目录

目录结构 源码目录运行后重定向输出目录结构

2,源码

2.1,config.ini

[engine]
work_path = ./tmp
max_task_num = 5

[mysql]
active = true
url = 10.0.23.132
user = root
passoword = root

2.2,task.json

{
    "task":[
        {
            "task_name": "task_1025_1",
            "test_project": "for",
            "version":"1.0",
            "describe": "错误代码"
        },
        {
            "task_name": "task_1025_2",
            "test_project": "for_2",
            "version":"1.0",
            "describe": "正确代码"
        }
    ]
} 

2.3,main.py

#!/usr/bin/env python
from src.engine import Engine

def main():
    config_file = "config.ini"
    task_file = "task.json"
    engine = Engine(config_file, task_file)
    engine.start()

if __name__ == '__main__':
    main()

2.4,src

2.4.1,config_info.py

import configparser
import json
import time, os
from src.record import TaskInfo, Status

class  ConfigInfo(object):
    global_conf = {}

    def __init__(self, conf_file, task_file):
        print('========  /********  config_info《__init__》start  *******/ =========')
        self.home_path = os.getcwd()
        self.__global_conf_file = self.home_path + "/" + conf_file
        self.__global_task_file = self.home_path + "/" + task_file
        self.loadConfig()
        print('========  /********  config_info《__init__》end  *******/ =========')

    def loadConfig(self):
        print('========  /********  config_info《loadConfig》start  *******/ =========')
        config = configparser.ConfigParser()
        config.read(self.__global_conf_file, encoding='utf8') 

        engine = {}
        engine["work_path"] = config.get("engine", "work_path")
        engine["max_task_num"] = config.get("engine", "max_task_num")
        self.global_conf["engine"] = engine

        mysql = {}
        mysql["url"] = config.get('mysql','url')
        mysql["user"] = config.get('mysql', 'user')
        mysql["password"] = config.get('mysql', 'passoword')
        self.global_conf["mysql"] = mysql

        print('========  /********  config_info《 loadConfig》end  *******/ =========')
        #print(self.global_conf)

    def loadTask(self, engine_info):
        print('========  /********  config_info《loadTask》start  *******/ =========')
        print("11111111111111111111111111111", self.__global_task_file)
        f = open(self.__global_task_file, encoding="utf-8")
        print("11111111111111111111111111111", self.__global_task_file)
        json_str = json.load(f)
        # print(json_str)
        engine_info.max_task = self.global_conf["engine"]["max_task_num"]
        if "task" in json_str:
            engine_info.start_time = time.ctime()
            engine_info.task_num = 0
            for task_json in json_str["task"]:
                task_info = TaskInfo()
                if self.getTaskInfo(task_json, task_info) < 0:
                    task_info.status = Status.ERROR
                engine_info.task_dict[task_info.task_name] = task_info
                engine_info.task_num += 1 
            print("engine_info.task_num:%d   enngine_info: %s"%(engine_info.task_num, engine_info))
        print('========  /********  config_info《loadTask》end  *******/ =========')

    def getTaskInfo(self, task_json, task_info):
        print('========  /********  config_info《getTaskInfo》start  *******/ =========')
        return_value = 0
        if "task_name" in task_json:
            task_info.task_name = task_json["task_name"]
            task_info.work_path = self.home_path + "/tmp/" + task_json["task_name"]
        else:
            print("loadTask error: task_name is required!")
            return_value = -1
        if "test_project" in task_json:
            task_info.test_project = self.home_path + "/test_task/" + task_json["test_project"]
        else:
            print("loadTask error: test_project is required!")
            return_value = -1
        if "version" in task_json:
            task_info.version = task_json["version"]
        if "describe" in task_json:
            task_info.describe = task_json["describe"]
        print('========  /********  config_info《getTaskInfo》end  *******/ =========')
        return return_value

2.4.2,engine.py

#!/usr/bin/env python
import sys, os, time
import json
from src.config_info import ConfigInfo
from src.record import EngineInfo, TaskInfo, Status
from src.task import Task
from multiprocessing import Process
from signal import SIGTERM
import atexit

class Engine(Process):
    def __init__(self, config_file, task_file):
        Process.__init__(self)
        print("========================//engine <init> start//===================================")
        self.config_file = config_file
        self.task_file = task_file
        self.config = ConfigInfo(self.config_file, self.task_file)
        self.engine_info_file = None
        self.HomeDir = None
        self.init_engine(self.config)
        self.init_environment()

        print("========================//engine <init> end//===================================")

    def init_engine(self, config):
        print("========================//engine <init_engine> start//===================================")
        if config.global_conf["engine"]["work_path"][:1] != '/':
            if config.global_conf["engine"]["work_path"][:2] == './':
                self.HomeDir = os.getcwd() + "/" + config.global_conf["engine"]["work_path"][2:]
            else:
                self.HomeDir = os.getcwd() + "/" + config.global_conf["engine"]["work_path"]
        self.engine_info_file = self.HomeDir + "/engine_info.json"
        self.stdout = self.HomeDir + "/stdout"
        self.stderr = self.HomeDir + "/stderr"

        print("========================//engine <init_engine> end//===================================")

    def init_environment(self):
        print("========================//engine <init_environment> start//===================================")
        if not os.path.exists(self.HomeDir):
            try:
                os.makedirs(self.HomeDir, mode=0o777)
            except OSError as e:
                sys.stderr.write('makedirs %s failed: %d (%s)\n' % (self.HomeDir, e.errno, e.strerror))
                
        print("task home_dir: ", self.HomeDir)
        os.chdir(self.HomeDir)  # 修改进程工作目录

        # 把之前的刷到硬盘上
        sys.stdout.flush()
        sys.stderr.flush()

        # 重定向标准文件描述符
        so = open(self.stdout, 'w+')
        se = open(self.stderr, 'w+')
        # os.dup2可以原子化的打开和复制描述符,功能是复制文件描述符fd到fd2, 如果有需要首先关闭fd2. 在unix,Windows中有效。
        # File的 fileno() 方法返回一个整型的文件描述符(file descriptor FD 整型)
        # os.dup2(so.fileno(), sys.stdout.fileno())
        # os.dup2(se.fileno(), sys.stderr.fileno()) #复制一份
        sys.stdout = so      #重定向
        sys.stderr = se
        

        # 注册退出函数,根据文件pid判断是否存在进程
        atexit.register(self.stop_engine)
        print("========================//engine <init_environment> end//===================================")

    def stop_engine(self):
        sys.stdout.flush()
        sys.stderr.flush()
        # 停止正在运行的任务
        if not os.path.exists(self.engine_info_file):
            print("engine_info_file not exists")
            sys.exit(-1)
        with open(self.engine_info_file, encoding='utf-8') as fd: 
            engine_info = json.load(fd)
            if "task_list" in engine_info:
                for task_name in engine_info["task_list"]:
                    pid = engine_info["task_dict"][task_name]["pid"]
                    self._killPid(pid)
            
    def _killPid(self, pid): 
        try:
            while 1:
                # 发送信号,杀死进程
                os.kill(pid, SIGTERM)
                time.sleep(0.1)
                message = "Process: {} is stopped.\n".format(pid)
                sys.stderr.write(message)
                sys.stderr.flush()
        except OSError as err:
            err = str(err)
            if err.find('No such process') > 0:
                print('No such process')
            else:
                print(str(err))
                sys.exit(1)

    def addTask(self, engine_info, task_name):
        print("========================//engine <addTask> start//===================================")
        task_info = engine_info.task_dict[task_name]
        task = Task(task_info)
        engine_info.task_list.append(task_name)
        task_info.status = Status.RUNNING
        task.start()
        engine_info.task_dict[task_name].pid = task.pid
        print("add task:", task_name, " successful!")
        print("========================//engine <addTask> end//===================================")

        
    def run(self, *args, **kwargs):
        engine_info = EngineInfo()
        engine_info.pid = os.getpid()
        # 从任务配置文件读取任务
        self.config.loadTask(engine_info)

        # 根据任务字典中任务状态和最大任务数创建任务
        for task_name, task_info in engine_info.task_dict.items():
            print(task_name, ":", task_info.status)
            if task_info.status == Status.WAITING:
                self.addTask(engine_info, task_name) 
        print("========================//engine <run> start//===================================")
        while(True):
            print("engine runing :", time.ctime())
            time.sleep(2)
            engine_info.end_time = time.ctime()
            engine_info.status = Status.RUNNING
            with open(self.engine_info_file, "w+", encoding='utf-8') as fd:
                task_dict = {}
                for task_name, task_info in engine_info.task_dict.items():
                    task_dict[task_name] = task_info.to_dict()
                engine_dict = engine_info.to_dict(task_dict)
                json.dump(engine_dict, fd, ensure_ascii=False)
            sys.stdout.flush()
            sys.stderr.flush()

        print("========================//engine <run> end//===================================")

2.4.3,record.py

import time
from enum import IntEnum

class Status(IntEnum):
    WAITING = 0
    RUNNING = 1
    FINISHED = 2
    WARNING = 3     #没导致程序奔溃
    ERROR = 4       #导致程序奔溃
    KILLED = 5      #杀死或删除
    TOTAL = 6
    ENUM_COUNT = 7  #状态总数


class TaskInfo(object):
    def __init__(self):
        self.task_name = None
        self.pid = 0
        #要测试的可执行文件信息
        self.test_project = None
        self.work_path = None   #该任务即进程的工作路径,所有运行时的文件都将保存在这
        #运行时获取
        self.start_time = time.ctime()
        self.end_time = None    #守护进程每次查询进程时更新,即每一个current_time覆盖当前的end_time
        self.status = Status.WAITING

    def to_dict(self):
        objs = {}
        for key, value in vars(self).items():
            objs[key] = value
        return objs
        # print(str)

class EngineInfo(object):
    def __init__(self):
        self.pid = 0
        self.max_task = 0
        self.task_num = 0       #总任务数
        self.task_dict = {}     #所有任务信息TaskInfo
        self.task_list = []     #当前正在跑的任务的名字
        self.start_time = time.ctime()
        self.end_time = None
        self.status = Status.WAITING

    def to_dict(self, task_dict=None):
        objs = {}
        for key, value in vars(self).items():
            if key == "task_dict":
                if task_dict != None:
                    objs[key] = task_dict
            else:
                objs[key] = value
        return objs
        # print(str)

2.4.3,task.py

import json
import shutil
import subprocess
import sys, time, os, atexit
from multiprocessing import Process
class Task(Process):
    def __init__(self, task_info):
        Process.__init__(self)
        print("--------------------------// task <init> start //--------------------------------")
        self.task_info = task_info
        self.HomeDir = task_info.work_path
        self.stdout = self.HomeDir + "/stdout"
        self.stderr = self.HomeDir + "/stderr"
        self.task_info_file = self.HomeDir + "/task_info.json"
        self.test_project_work_path = self.HomeDir + "/test_project"
        self.test_project_stdout = self.test_project_work_path + "/stdout"
        self.test_project_stderr = self.test_project_work_path + "/stderr"
        self.applicationName = self.task_info.test_project

        print("--------------------------// task <init> end //--------------------------------")
    
    def init_environment(self):
        print("========================//task <init_environment> start//===================================")
        # 创建task进程工作目录
        if os.path.exists(self.HomeDir):
            shutil.rmtree(self.HomeDir)
        try:
            os.makedirs(self.HomeDir, mode=0o777)
        except OSError as e:
            sys.stderr.write('makedirs %s failed: %d (%s)\n' % (self.HomeDir, e.errno, e.strerror))
        # 创建测试工程工作目录
        try:
            os.makedirs(self.test_project_work_path, mode=0o777)
        except OSError as e:
            sys.stderr.write('makedirs %s failed: %d (%s)\n' % (self.test_project_work_path, e.errno, e.strerror))
                
        print("task home_dir: ", self.HomeDir)
        print("task test_progect_work_path: ", self.test_project_work_path)
        os.chdir(self.HomeDir)  # 修改进程工作目录

        # 把之前的刷到硬盘上
        sys.stdout.flush()
        sys.stderr.flush()

        # 重定向标准文件描述符
        so = open(self.stdout, 'w+')
        se = open(self.stderr, 'w+')
        sys.stdout = so
        sys.stderr = se

        # 注册退出函数,根据文件pid判断是否存在进程
        atexit.register(self.killApplication)
        print("========================//task <init_environment> end//===================================")
        
    def killApplication(self):
        sys.stdout.flush()
        sys.stderr.flush()
        cmd = "killall -9 {}".format(self.task_info.test_project)
        os.system( cmd )

        
    def run(self, *args, **kwargs):
        print("--------------------------// task <run> start //--------------------------------")
        
        self.init_environment()
        self.task_info.pid = str(os.getpid())
        # 重定向测试工程标准文件描述符
        so = open(self.test_project_stdout, 'w+')
        se = open(self.test_project_stderr, 'w+')
        # 启动测试任务
        # sql = "nohup {} {} {} > {}".format(self.task_info.test_project, self.task_info.config_file, 
        #                                     self.task_info.source_file, self.test_project_log)
        # os.system( sql )
        subprocess.Popen([self.task_info.test_project],
                            bufsize=0, stdout=so, stderr=se, cwd=self.test_project_work_path)
        
        while(True):
            sys.stdout.write('%s:task child process runing\n' % (time.ctime()))
            time.sleep(3)
            print("run while ", self.task_info.task_name)
            self.task_info.end_time = time.ctime()
            with open(self.task_info_file, "w+", encoding="utf-8") as fd:
                task_dict = self.task_info.to_dict()
                json.dump(task_dict, fd, ensure_ascii=False)
            sys.stdout.flush()
            sys.stderr.flush()

        print("========================//task <run> end//===================================")

3,测试代码

3.1,for.cpp

#include <iostream>

int main()
{
    int a[10];
    for(int i=0; i<30; i++) {
        a[i] = i;
        std::cout << i << std::endl;
    } 
    return 0;
}

3.2,for_2.cpp

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> a;
    for(int i=0; i<20; i++) {
        a.push_back(i);
        std::cout << i << std::endl;
    } 
    return 0;
}

3.3,c++编译脚本

#!/bin/bash

gcc for.cpp -o for -lstdc++
gcc for_2.cpp -o for_2 -lstdc++
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值