MVC系统有三个子系统。Model 包含业务逻辑以及所有由系统处理的数据。它包括一个针对外部存储(如一个数据库)的接口。通常模型(model)只暴露一个公共的API给其它的组分。 View包含显示数据的对象。Controller管理与用户的交互(Controller处于Model和view中间)。在现代的UI工具包中,View和Controller组分是被集成在一起的。
上面的这段话是从《wxPython in action》中摘录出来的,说的是GUI程序设计的模式。一个小小的软件,为了让它跑起来并顺利完成相应的任务,折腾来折腾去。按照MVC模式,先把模型建立了起来:模型被单独封装成一个类,只向视图与控制器提供开始、结束采集的命令传输接口以及一个用于数据传输的队列(Queue.Queue类)。把只能执行一次的threading.Timer类改造了一下,构建了一个可以周期性执行的定时器。下位机还是用Arduino模拟(后面有时间的话,直接就用Arduino了,减少工序,有现成的就用现成的,尽量避免做从零开始写程序、画PCB、选购元件、焊接并调试电路板诸如此类的事情)。测试的时候没有GUI的参与,只在脚本里面运行了一下,所以在主程序里面触发了一个定时器,用来结束程序。启动,等待程序结束,检查数据库。二十秒以内还好,停止命令发出后,程序可以退出,但是测量时间一长,程序就不能退出了。基础不扎实,连程序到底运行到了哪里都弄不清楚。用IDE调试了半天,大概知道了有一个定时器没有退出,但还是确定不了原因,再加上用于结束程序的定时器的干扰,动不动就抛异常。大概说一下,开始的时候构建出来的定时器是run函数递归调用自身,以此来实现周期性运行(秒级的,影响不是很大),这样做的代价是大量函数进栈,停止时需逐层返回。后来改了下,不再借助递归了,耗费的资源应该会少一些。用trace跟踪了一下,产生了四万多行的跟踪信息,重定向到txt文档中后,文档有两兆多。跟踪信息的最后一部分显示程序还在threading里面游荡,确实是自己构建的那个定时器没有正常退出。找不到问题,就暂时扔下了。
费尽脑筋想的时候想不到,刚躺到床上立马就意识到了问题出在哪里。可能就是那个Queue。由于没有GUI参与,不需要绘图,主程序里面没有进行出队列的操作,但处理数据的线程里面一直在进行入队操作,Queue满了以后,有可能把线程给阻塞了,所以线程无法退出。懒得起身开电脑了,在手机上的解释器里面写了几句,发现队列满了之后确实会发生阻塞。看了一下python官方文档,果然是这样:
Insertion will block once this size has been reached, until queue items are consumed.
中午加了个python群,感觉太深入的问题没有人回答,只能自己一遍一遍调试找症节。独自寻求解决方案的过程中确实能学到不少东西,但是,个中滋味恐怕也只有自己能体会。
|