使用Paho的Python应用程序MQTT和使用Tkinter的GUI出现重大性能问题(select.select)

时间:2019-07-16 11:27:39

标签: python performance tkinter mqtt paho

我正在构建一个应用程序,该应用程序使用MQTT通过简单的GUI发布/接收数据以显示接收到的数据以及打开/关闭切换,如果发生更改,则使用MQTT发布消息。

该应用程序可以正常运行,但是太笨拙了。

我使用了CProfile,发现分配给它最多时间的函数是“ select.select”,所以我的问题是如何提高代码的性能。 CProfile Output(sort=tottime) CProfile Output(sort=cumtime)

注意:我试图在不同的线程上运行MQTT,但是我必须访问Tkinter不允许的MQTT函数中的Tkinter对象(这是我的理解)

其余代码(如果需要):https://www.codepile.net/pile/K2VvKz2y

from tkinter import *
import paho.mqtt.client as mqtt
import gui

running = True

def update_running():
    global running
    running = False
    root.destroy()


def update_meters(topic, value):
    if topic == "home/office/temperature":
        office_temperature_meter.reading.set(value)
    elif topic == "home/bed/temperature":
        bed_temperature_meter.reading.set(value)
    elif topic == "home/living/temperature":
        living_temperature_meter.reading.set(value)


def on_connect(client, userdata, flags, rc):
    print("Connected With Result Code "+rc)


def on_message(client, userdata, message):
    print(message.topic + " Received: " + message.payload.decode())
    update_meters(message.topic, message.payload.decode())


# Establishing Connection
broker_url = "iot.eclipse.org"
broker_port = 1883

client = mqtt.Client("G2K_RaspberryPie3_x01")
client.on_connect = on_connect
client.on_message = on_message
client.connect(broker_url, broker_port)

client.subscribe("home/office/temperature", qos=1)
client.subscribe("home/bed/temperature", qos=1)
client.subscribe("home/living/temperature", qos=1)
###########

# Initiating Main Application Window
root = Tk()
root.geometry("{0}x{1}+0+0".format(root.winfo_screenwidth(), root.winfo_screenheight()))
root.focus_set()
root.title("G2K: Smart Home")
root.protocol("WM_DELETE_WINDOW", update_running)
###########

# Office Frame
office_frame = gui.FrameCreate(250, 650, "LightGrey", 20, 20, "Office", 85)
root.update()
office_lights_button = gui.ToggleButton(10, 100, "Lights", office_frame.frame)
office_conditioner_button = gui.ToggleButton(10, 200, "Air Conditioner", office_frame.frame)
office_temperature_meter = gui.ReadingMeter(10, 300, "Temperature", office_frame.frame)
###########

# Bedroom Frame
bed_frame = gui.FrameCreate(250, 650, "LightGrey", 300, 20, "Bedroom", 75)
root.update()
bed_lights_button = gui.ToggleButton(10, 100, "Lights", bed_frame.frame)
bed_conditioner_button = gui.ToggleButton(10, 200, "Air Conditioner", bed_frame.frame)
bed_temperature_meter = gui.ReadingMeter(10, 300, "Temperature", bed_frame.frame)
###########

# Livingroom Frame
living_frame = gui.FrameCreate(250, 650, "LightGrey", 590, 20, "Living Room", 60)
root.update()
living_lights_button = gui.ToggleButton(10, 100, "Lights", living_frame.frame)
living_conditioner_button = gui.ToggleButton(10, 200, "Air Conditioner", living_frame.frame)
living_temperature_meter = gui.ReadingMeter(10, 300, "Temperature", living_frame.frame)
###########


while 1:
    if running:
        # constantly update the GUI
        root.update()
        # constantly check if any messages arrived on subscribed topics
        client.loop()

        # Check if state is not changed, to avoid sending redundant requests.
        if office_lights_button.button_state != office_lights_button.button_prev_state:
            client.publish(topic="home/office/light", payload=int(office_lights_button.button_state), qos=1,
                           retain=False)
            office_lights_button.button_prev_state = office_lights_button.button_state

        if office_conditioner_button.button_state != office_conditioner_button.button_prev_state:
            client.publish(topic="home/office/conditioner", payload=int(office_conditioner_button.button_state), qos=1,
                           retain=False)
            office_conditioner_button.button_prev_state = office_conditioner_button.button_state

        # Check if state is not changed, to avoid sending redundant requests.
        if bed_lights_button.button_state != bed_lights_button.button_prev_state:
            client.publish(topic="home/bed/light", payload=int(bed_lights_button.button_state), qos=1,
                           retain=False)
            bed_lights_button.button_prev_state = bed_lights_button.button_state

        if bed_conditioner_button.button_state != bed_conditioner_button.button_prev_state:
            client.publish(topic="home/bed/conditioner", payload=int(bed_conditioner_button.button_state), qos=1,
                           retain=False)
            bed_conditioner_button.button_prev_state = bed_conditioner_button.button_state

        # Check if state is not changed, to avoid sending redundant requests.
        if living_lights_button.button_state != living_lights_button.button_prev_state:
            client.publish(topic="home/living/light", payload=int(living_lights_button.button_state), qos=1,
                           retain=False)
            living_lights_button.button_prev_state = living_lights_button.button_state

        if living_conditioner_button.button_state != living_conditioner_button.button_prev_state:
            client.publish(topic="home/living/conditioner", payload=int(bed_conditioner_button.button_state), qos=1,
                           retain=False)
            living_conditioner_button.button_prev_state = living_conditioner_button.button_state

1 个答案:

答案 0 :(得分:0)

尝试客户端类 loop_start() 方法。由于它运行一个单独的线程,它不会过多地影响 GUI 的主循环。我只在 pyqt5 中尝试过,但它也可以与 tk 一起使用。

移除 while true 循环并在最后添加 client.loop_start() 和 tks mainloop。

https://pypi.org/project/paho-mqtt/#client