首页 > 解决方案 > 多线程 Python 程序中的计时器漂移

问题描述

我目前正在为一个项目开发数据记录器。数据记录器应从车载访问平台上的两个不同 CAN 总线系统读取数据,解码原始数据并将其定期存储在 json 文件中,该文件将在设备关闭之前上传到 blob 存储。我正在使用基于树莓派的硬件并在 Python 3.7 中对其进行编程。除了定期存储数据外,一切正常。在 json 文件中创建和存储数据开始良好,并在一分钟后以 100 毫秒的步长完成,您开始看到两个数据点之间的时间漂移​​。如果您将代码运行数小时,则数据点之间的时间会长达数分钟。

我知道 Linux 不是 RTOS,但应该可以以 100 毫秒的步长保存数据。那么我的方法是错误的吗?

我尝试使用 threading.Event 而不是睡眠,我还尝试将它作为多个进程而不是线程运行。

这是我遇到问题的函数的代码:

def create_json_file():
    global FILE_INITIALIZED
    global FILE_NAME
    once = bool

    try:
        while not stop_create.is_set():
            if not store_data:
                next_call = time.time()

            if  store_data == True:
                if not once:
                    next_call = time.time()
                    once = True
                # Calculate the offset taking into account daylight saving time
                utc_offset_sec = time.altzone if time.localtime().tm_isdst else time.timezone
                utc_offset = datetime.timedelta(seconds=-utc_offset_sec)
                timestamp = datetime.datetime.now().replace(tzinfo=datetime.timezone(offset=utc_offset)).isoformat()
                tmp_json_dict = {}
                tmp_json_dict['deviceId'] = DEVICE_ID
                tmp_json_dict['timestamp'] = timestamp
                tmp_json_dict.update(processed_data)

                if FILE_INITIALIZED == False:
                    first_json_dict = []
                    first_json_dict.append(tmp_json_dict)
                    FILE_NAME = './storage/' + DEVICE_ID + datetime.datetime.now().strftime("_%Y%m%d_%H%M.json")
                #/home/pi/Test
                if FILE_INITIALIZED == False:
                    with open(FILE_NAME,"w+") as outputfile:
                        json.dump(first_json_dict,outputfile,indent=4,sort_keys=False)
                        FILE_INITIALIZED = True
                        first_json_dict.clear()
                else:
                    with open(FILE_NAME, "r+") as file:
                        file_data = json.load(file)
                        file_data.append(tmp_json_dict)
                        file.seek(0)
                        json.dump(file_data, file, indent=4)
                
                next_call = next_call + INTERVAL_TIME
                time.sleep(abs(next_call - time.time()))

    except Exception as err:
        logging.exception(err)
        if not stop_create.is_set():
            # Only log exception if we were not going to stop the thread
            # When quitting, the main thread calls close() on the serial device
            # and read() may throw an exception. We don't want to display it as
            # we're stopping the script anyway
            global thread_exception_file
            thread_exception_file = sys.exc_info()

这是一段时间后有漂移的输出:

[
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:24:13.480148+01:00"
    },
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:24:13.580144+01:00"
    },
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:24:13.679995+01:00"
    },
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:24:13.780075+01:00"
    },
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:24:13.880101+01:00"
    },
...
...
...
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:25:20.078147+01:00"
    },
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:25:20.316632+01:00"
    },
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:25:20.556145+01:00"
    },
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:25:20.797479+01:00"
    },
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:25:21.041794+01:00"
    },
    {
        "deviceId": "Prototype_FieldTest_P300KS_Facelift",
        "timestamp": "2020-11-28T22:25:21.288214+01:00"
    }
]

标签: pythonmultithreadingraspberry-pi

解决方案


推荐阅读