EOFError:跑出类内的输入 [英] EOFError: Ran out of input inside a class

查看:58
本文介绍了EOFError:跑出类内的输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码,需要一次读取多个传感器.我已经设置了线程和多处理功能来为我完成此任务.当线程和多处理代码不在主类之外时,它可以正常工作,但该类无法使用其检索的数据.当我将多线程代码插入类中时,遇到了EOFError: Ran out of input错误.

I have the following code where I need to read multiple sensors at a time. I have set up threading and multiprocessing to do this task for me. When the threading and mutliprocessing code is outside of the main class, it works fine but the class can't use the data it retrives. When I put the mutlithreading code insdie the class, I run into an EOFError: Ran out of input error.

这是代码:

import os
import multiprocessing
from multiprocessing import Process, Pool
import threading
import queue
import tkinter as tk
from tkinter import *
from tkinter import ttk
import time
import minimalmodbus
import serial
minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL = True
THREAD_LOCK = threading.Lock()

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)

        self.pack()

        self.first_gas_labelframe = LabelFrame(self, text="Gas 1", width=100)
        self.first_gas_labelframe.grid(row=0, column=0)

        self.value_label = Label(self.first_gas_labelframe, text="Value")
        self.value_label.grid(row=0, column=0)

        self.unit_label = Label(self.first_gas_labelframe, text="Unit")
        self.unit_label.grid(row=1, column=0)

        self.temp_label = Label(self.first_gas_labelframe, text="Temp")
        self.temp_label.grid(row=2, column=0)

        self.temp_label6 = Label(self.first_gas_labelframe6, text="Temp")
        self.temp_label6.grid(row=2, column=0)

        self.timer_button = tk.Button(self, text='Start', command=self.start_run)
        self.timer_button.grid(row=2, column=0)


    def start_run(self):
        self.all_thread()

    def all_thread(self):
        thread = threading.Thread(target=self.all_process)
        thread.start()

    def all_process(self):
        all_ports = port_num()
        gas = minimalmodbus.Instrument("COM3", 1)
        gas.serial.baudrate = 9600
        gas.serial.bytesize = 8
        gas.serial.parity = serial.PARITY_NONE
        gas.serial.stopbits = 1
        gas.serial.timeout = 0.25
        gas.mode = minimalmodbus.MODE_RTU

        gas_list = [gas]
        processes = []
        while len(gas_list) > 0:
            val = 1
            with THREAD_LOCK:
                for sen in gas_list:
                    proc = Process(target=self.main_reader, args=(sen, val))
                    processes.append(proc)
                    proc.start()
                    val += 1
                for sen in processes:
                    sen.join()
                time.sleep(1)

    def main_reader(sen, val):
        try:
            read = sen.read_registers(0,42)
        except OSError:
            read = "Communication Error"
        except ValueError:
            read = "RTU Error"
        print(read)

if __name__ == '__main__':
    root = tk.Tk()
    root.geometry("1000x600")
    app = Application()
    app.mainloop()

通过一些调试,问题发生在proc.start()处,但是proc有数据.列表中也有数据,这就是为什么我很困惑为什么输入用完了的原因.注意:在我的代码中,gas_list

With some debugging, the problem happens at proc.start() but proc has data. The lists have data too, which is why I am confused why it is running out of input. Note: in my code there are six entries in the gas_list

推荐答案

您不能使用这样的多重处理(可以,但是结果将是不可预测的)-当您创建新进程时,minimalmodbus.Instrument对象将从list不会作为参考传递,而是作为一个全新的对象传递.每当您start()一个multiprocess.Process实例时,Python实质上都会运行一个全新的Python解释器实例,并且由于不同的进程获得了不同的堆栈,因此它们无法共享内部内存,因此Python实际上会腌制所传递的参数,将其发送给Process并然后在此处将它们解开,产生一种幻觉,即两个进程(父级和子级)都具有相同的数据.

You cannot use multiprocessing like that (well, you can, but the result will be unpredictable) - when you create a new process your minimalmodbus.Instrument object from the list doesn't get passed as a reference but as a whole new object. Python essentially runs a completely new Python interpreter instance whenever you start() a multiprocess.Process instance and since different processes get different stacks they don't get to share the internal memory so Python actually pickles the passed arguments, sends them to the Process and then unpickles them there creating an illusion that both processes (the parent and the child) have the same data.

如果您没有创建新的multiprocessing.Process而是调用self.main_reader(pickle.loads(pickle.dumps(sen)), val)(val也被腌制,但作为通用名称,在这里并不重要),您就可以自己观察它.

You can observe it yourself if instead of creating a new multiprocessing.Process you call self.main_reader(pickle.loads(pickle.dumps(sen)), val) (val also gets pickled but as a generic it's not of any importance here).

Application.main_reader()方法(尽管很奇怪地定义了)也发生了同样的过程-设置方法是在子过程中实际上重新创建了整个Application实例,以便Python可以调用其main_reader()方法.

The very same process happens to the Application.main_reader() method (although weirdly defined), too - the way you have it set up is that your whole Application instance actually gets recreated in the sub-process so that Python can call its main_reader() method.

您可以做的是传递所需的参数,以将原始对象重新创建给子流程函数,然后在函数启动时创建对象.例如,如果您将Application.all_process()方法修改为:

What you can do instead is to pass needed arguments to recreate your original object to the sub-process function, and then have your object created when your function starts. For example, if you modify your Application.all_process() method as:

def all_process(self):
    gas = {"__init__": ("COM3", 1)
           "serial": {
               "baudrate": 9600,
               "bytesize": 8,
               "parity": serial.PARITY_NONE,
               "stopbits": 1,
               "timeout": 0.25
           },
           "mode": minimalmodbus.MODE_RTU}

    gas_list = [gas]
    processes = []
    while len(gas_list) > 0:
        val = 1
        for sen in gas_list:
            # we'll be calling the main_reader function outside of the Application instead
            proc = multiprocessing.Process(target=main_reader, args=(sen, val))
            processes.append(proc)
            proc.start()
            val += 1
        for sen in processes:
            sen.join()
        time.sleep(1)
        # you do plan to exit this loop, right?

然后在Application类之外将main_reader()函数定义为:

And then have your main_reader() function defined outside of the Application class as:

def main_reader(data, val):  # notice it's outside of the Application scope
    sen = minimalmodbus.Instrument(*data["__init__"])  # initialize Instrument
    for k, v in data["serial"].items():  # apply the serial settings
        setattr(sen.serial, k, v)
    sen.mode = data["mode"]  # set the mode
    try:
        read = sen.read_registers(0, 42)
    except OSError:
        read = "Communication Error"
    except ValueError:
        read = "RTU Error"
    print(read)

它应该停止引发错误.另外,您在原始代码中使用了threading.Lock -我不知道您尝试使用它实现什么,但是最肯定的是它并没有按照您的想象去做.

It should stop throwing errors. Also, you've used threading.Lock in your original code - I don't know what you were trying achieve with it, but it most certainly doesn't do what you think it does.

这篇关于EOFError:跑出类内的输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆