python 如何运行两个依赖线程,但仍然控制它们应该在何时执行?

dpiehjr4  于 2023-04-04  发布在  Python
关注(0)|答案(1)|浏览(114)

我有一个虚拟的opcua服务器,它随机生成值。我创建了一个客户端,它必须从服务器读取值,每隔10秒,它应该将这些值存储在日志文件中。由于服务器非常快,在阅读值10秒后立即存储数据可能会导致延迟客户端读取服务器新生成的数据。这就是为什么我考虑使用多线程。
我设置了两个线程:一个线程用于阅读客户端,第二个线程用于存储数据。
线程的工作方式如下:首先,代码需要从客户端读取,一旦10秒的周期完成,存储数据的线程被触发,但它不应该中断另一个线程的阅读。

from opcua import Client
import time
from datetime import datetime
import threading

class client:
    def __init__(self, url="opc.tcp://127.0.0.1:8080", store_cycle = 10, read_cycle=1):
        self.url = url
        self.store_cycle = store_cycle
        self.read_cycle = read_cycle
    def connect_to_server(self):
        clt = Client(self.url)
        clt.connect()
        var1 = clt.get_node("ns=2;s=var1_val")
        var2 = clt.get_node("ns=2;s=var2_val")
        return var1,var2

    def read_from_client(self,var1,var2):
        iterator = 0
        logs = []
        dt = datetime.now().strftime("%Y-%m-%d_%Hh%Mm%Ss")
        while iterator < (self.store_cycle/self.read_cycle):
            iterator+=1

            val1 = var1.get_value()
            val2 = var2.get_value()

            time.sleep(self.read_cycle)

            logs.append(f"datachange_notification ns=2;s=var1_val {val1}")
            logs.append(f"datachange_notification ns=2;s=var2_val {val2}")
            print(val1)
            print(val2)
        print("log created")
        return logs,dt

    def store_values(self,logs,dt):
        with open(f"logs/message_{dt}.log", 'w+') as logfile:
            logfile.write('\n'.join(logs))
            time.sleep(10)

c = client()
var1,var2 = c.connect_to_server()
while True:
    t1 = threading.Thread(target=c.read_from_client, args=(var1,var2))
    logs,dt = t1.run()
    t2 = threading.Thread(target=c.store_values, args=(logs,dt))
    t2.run()

这是我目前为止的方法,但我对多线程只有很少的经验。有什么帮助吗?

kh212irz

kh212irz1#

我看到这里有一些问题。可能还有其他问题。我没有太深入地研究你想做的事情。
你调用t1.run()t2.run()。这通常是一个错误。你的主程序不创建任何线程。它创建了两个Thread * 对象,* 但这不是一回事。如果你不调用t1.start()t2.start(),实际上不会创建任何线程。
当您调用start()函数时,它会创建一个新线程,然后 new thread 调用run()函数。
你的t1.run()函数返回一个值。但是当你start一个单独的线程时,run()函数返回的值将被忽略。如果你需要从一个线程到另一个线程传递一个值,你必须通过改变两个线程都可以访问的变量的值或对象的状态来完成。
store_values函数中没有循环,并且您只尝试调用该函数一次。因此,它只会调用logfile.write('\n'.join(logs)) * 一次。*
我设置了两个线程:一个线程用于阅读客户端,第二个线程用于存储数据。
我只需要一个线程就可以完成,而不是每次循环都盲目地休眠10秒,我会 * 计算 * 休眠的时间,这样它就可以精确地每10秒从客户端读取一次。类似于下面的代码(伪代码):

import time

next_wakeup_time = time.time()
while True:
    next_wakeup_time = next_wakeup_time + 10.0
    ...read from the client...
    ...store the values...
    time_now = time.time()
    sleep_duration = next_wakeup_time - time_now
    if sleep_duration >= 0.0:
        time.sleep(sleep_duration)
    else:
        print("Uh Oh! Missed a deadline!")
        ...maybe recover from error if we missed a "hard" real-time
        ...deadline (see below.)
        next_wakeup_time = time.time()
  • 精度将受到系统时钟精度的限制,无论您使用的是什么操作系统和硬件平台。您需要每10秒执行一次操作,这就是real-time requirement的一个例子。如果您的程序必须在“正确的时间”读取服务器,那么这就称为“硬”实时要求。另一方面,如果这只是一个“好主意”,“这是一个 * 软 * 实时的要求。

如果“正确的时间”是大约1毫秒或更短的窗口,那么您可能希望在运行专门的real-time operating system的专用硬件上运行。如果窗口为几十毫秒或更长,那么您可能可以使用普通的桌面或服务器操作系统,但您可能仍然希望在专用硬件上运行(即,在没有同时运行其他程序的计算机上。)

相关问题