python fork杀死子进程,循环任务

37 篇文章 0 订阅

背景

一个车联网项目,车辆的状态数据(电池,车速,里程等数据)每隔30秒上传一次到服务器A。
现将机器A上mysql的数据定时上传到机器B的接口。
可使用的方法:
1、开启定时任务crontab,定时将机器A中mysql的数据上传到机器B 接口。
2、 使用循环,但是每个循环之间使用 time.sleep(1000)。每次循环上传一定数量的数据。
代码如下:
vehicle_uploader.py

import requests
import time
import json
import hashlib
import pymysql


class VehicleUploader(object):
    def __init__(self):

        self.url = "http://120.178.240.24/jci/dmiot"
        self.headers = {'Content-Type': 'application/json', "Accept": "text/html,application/xhtml+xml,*/*"}
        self.auth_code = "43532546653"
        self.account = "100001"


        self.mysql_url = "ehjbd.cn"
        self.user = "root"
        self.passwd = "shui555629"
        self.db = "vehicle_db"
        self.conn = pymysql.connect(self.mysql_url,  self.user, self.passwd, self.db, cursorclass=pymysql.cursors.DictCursor)

    def read_data(self):

        sql = "select * from vehicle_db order by create_time desc limit 1000"
      

        cursor = self.conn.cursor()
        cursor.execute(sql)
        rows = cursor.fetchall()
        results = []
        ids = []
        for row in rows:
            group = {}
            ids.append(row.get("id", ""))
            recodrd_id = row.get("id", "")
            vin =  row.get("vin", "")
            up_time = str(row.get("push_time", ""))
            longitude = row.get("longitude", "")
            latitude = row.get("latitude", "")
            status = row.get("vehicle_status", "")
            battery_status = row.get("battery_status", "")
            soc =  row.get("soc", "")

            group.update({"recodrd_id": recodrd_id, "vin": vin, "up_time": up_time, "longitude":longitude, 
                          "latitude":latitude, "status":status, "battery_status":battery_status, "soc":soc, 
                        })
            results.append(group)
            print(group)
        return results, ids

    def update_data(self, ids):
        idss = ",".join([str(i) for i in ids])
        sql = "update vehicle_db set syn_flag=1 where id in ({ids})" .format(ids=idss)
        print(sql)
        cursor = self.conn.cursor()
        cursor.execute(sql)
        self.conn.commit()

    def run(self):
        data = {}
        results, ids = self.read_data()
        t = "T" + time.strftime("%Y%m%d")  + "Z"
        data.update({"account":self.account, "PushTime":t, "auth_code": self.auth_code, "result": results })

        data = json.dumps(data)
        r =requests.post(self.url, headers=self.headers, data=data)
        resp = json.loads(r.text)
        print(resp)

        if resp["code"] == 0:
            self.update_data(ids)
        
if __name__ == "__main__":
    uploader = VehicleUploader()
    uploader.run()
    print("task done .....")

服务部署的时候可以加 linux crontab 任务

crontab -e

*/2  *  *  *  *  python3 vehicle_uploader.py

问题

如果使用crontab 任务, 可能会出现这样的问题,上一次启动的任务还未执行完,下一次的任务已经启动了,导致启动的任务很多, 但是完成的很少。(以上代码不一定会出现这种问题,但是其他的场景可能因为程序执行较长或者阻塞出现这种问题)。不同任务有重复执行的工作,而且占用服务器资源。

如果去掉定时任务改成循环执行,如下:

if __name__ == "__main__":
    while True:
        uploader = VehicleUploader()
        uploader.run()
        time.sleep(60)
    print("task done .....")

如果由于网络或者数据库等原因导致一个循环阻塞或者执行时间较长,势必影响正常的任务执行。

解决方法

fork一个子进程执行任务,父进行可以对子进程进行管理。 当子进程执行时间过长(可能由于异常导致执行时间超过正常时间),父进程可以杀死子进程,并在下一个循环中重新开启一个子进程执行之前的任务。

代码如下:

import os
import signal            # 导入signal 包

if __name__ == "__main__":
    while True:
        pid = os.fork()           # fork 子进程
        if pid == 0:
            # 执行任务
            uploader = VehicleUploader()
            uploader.run()
        else:
            time.sleep(30)
            os.kill(pid, signal.SIGKILL)  # kill子进程
        time.sleep(60)
    print("task done .....")

说明: 与os.fork, os.kill, 子进程相关的资料请查看 python os 的文档。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值