python - 将包含串行初始化的 python 脚本导入烧瓶应用程序
问题描述
我想以脚本的形式将一些函数(我们称之为 controller.py)导入到烧瓶应用程序中作为 Web 服务。我们将烧瓶应用程序称为 api.py。
问题是,在 controller.py 中有一个 pyserial 声明。
控制器.py:
import serial
ser = serial.Serial('COM31', 9600,timeout=2)
def serial_function(foo):
ser.write(foo)
reply = ser.read()
return reply
api.py:
from flask import Flask
import controller as cont
app = Flask(__name__)
@app.route('/function/<foo>',methods=['GET'])
def do_function(foo):
data=cont.serial_function(foo)
return data
if __name__ == '__main__':
app.run('0.0.0.0', 80,True)
但我得到了这个错误:
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 都会加载/解释文件,并通过这样做,执行在模块根级别找到的所有代码。(如果您想深入了解,可以参考这个出色的答案:如果 __name__ == "__main__": do? 会怎样?)
此外,在调试模式下,Flask 将启动 2 个进程(一个用于监视源代码,当发生更改时,重新启动第二个,这是真正处理请求的进程),在生产模式下,您可以创建更多线程或启动服务器时的进程,通过这样做,您的模块至少被导入两次=>串行打开冲突。
一个可能的解决方案是从您的模块中删除串行端口的初始化,并在您的方法中使用上下文管理器语法:
def serial_function(foo):
with serial.Serial('COM31', 9600,timeout=2) as ser:
ser.write(foo)
reply = ser.read()
return reply
这样,您将在每次读取时打开(和关闭)您的串行端口。
但是,如果您有多个客户端同时向您的网络服务器发出请求,您仍然必须处理并发访问。
编辑:如果,正如您在评论中所说,您只需要打开一次串行端口,则需要将其封装在一个特定对象中(可能使用单例模式),如果尚未打开串行端口,该对象将负责打开串行端口打开:
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
推荐阅读
- search - 按 attr_stream_size 对 solr 中的文档进行排序
- python - Pandas 数据框产生 KeyError: -1
- ios - 单击以选择时间 Xcode 重复 mp3 文件
- modelica - 如何在 Dymola 中跟踪用于计算管道质量的参数和方程?
- javascript - 比较 js / jquery 中的日期
- sorting - Google 表格可排序箭头
- android - Android - 删除所有应用程序,设置和自定义应用程序除外
- sql - 简化 sql 查询(日期到期间)
- javascript - 关于JS中闭包的内存效率
- git - GIT sourcetree - 我们需要创建本地分支来拉新的远程分支吗?