将包含串行初始化的python脚本导入flask应用程序

将包含串行初始化的python脚本导入flask应用程序,python,flask,pyserial,Python,Flask,Pyserial,我想以脚本的形式将一些函数作为web服务导入flask应用程序,我们称之为controller.py。让我们调用flask应用程序api.py 问题是,在controller.py中,有一个pyserial声明 controller.py: 导入序列号 ser=serial.serial('COM31',9600,超时=2) def串行_功能(foo): ser.write(foo) reply=ser.read() 回覆 api.py: 从烧瓶导入烧瓶 将控制器作为cont导入 app=烧瓶

我想以脚本的形式将一些函数作为web服务导入flask应用程序,我们称之为controller.py。让我们调用flask应用程序api.py

问题是,在controller.py中,有一个pyserial声明

controller.py:

导入序列号
ser=serial.serial('COM31',9600,超时=2)
def串行_功能(foo):
ser.write(foo)
reply=ser.read()
回覆
api.py:

从烧瓶导入烧瓶
将控制器作为cont导入
app=烧瓶(名称)
@app.route('/function/',methods=['GET'])
def do_功能(foo):
数据=连续串行函数(foo)
返回数据
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
应用程序运行('0.0.0.0',80,真)
但我有一个错误:

raise SerialException("could not open port %s: %s" % (self.portstr, ctypes.WinError()))
serial.serialutil.SerialException: could not open port COM31: [Error 5] Access is denied.
Flask似乎一次又一次地尝试导入controller.py,并且重新初始化了串行端口


是否有某种方法可以实现上述目标?

代码的主要问题是串行对象创建直接在模块的代码中。这样,每次导入模块时,python都会加载/解释文件,并通过这样做,执行在模块根级别找到的所有代码。(如果你想深入了解更多,可以参考这个极好的答案:)

此外,在调试模式下,Flask将启动2个进程(一个用于监视源代码,当更改时,重新启动第二个进程,这是真正处理请求的进程),在生产模式下,您可以在启动服务器时创建更多的线程或进程,您的模块至少导入了两次=>串行打开冲突

一种可能的解决方案是从模块中删除串行端口的初始化,并在方法中使用:

def serial_function(foo):
    with serial.Serial('COM31', 9600,timeout=2) as ser:
        ser.write(foo)
        reply = ser.read()
        return reply
这样,您将在每次读取时打开(和关闭)串行端口

但是,如果有多个客户端同时向Web服务器发出请求,那么您仍然需要处理并发访问

编辑: 如您在评论中所说,如果您只需要打开一次串行端口,则需要将其封装在特定对象中(可能使用单例模式),该对象将负责打开尚未打开的串行端口:

class SerialProxy:
    def __init__(self):
        self.__serial = None

    def serial_function(self, foo):
        if self.__serial is None:
            self.__serial = serial.Serial('COM31', 9600,timeout=2)
        self.__serial.write(foo)
        reply = self.__serial.read()
        return reply

谢谢你的回答,但有没有解决方案,不重新打开串行在每次通话。我希望此脚本与arduino或任何其他MCU通信,这些MCU在每次打开串行通信时都会重新启动。@AlvinHardian:我根据这些新信息更新了我的答案(将其添加到原始问题中;)