1.工具背景
1.1工具目标
1、使用python开发界面工具
1.2工具特点
1、用户在界面上进行操作
2、工具需要处理大量数据(CPU+内存)
3、工具需要进行持续性任务(高CPU占用)
2.界面程序设计方案
2.1方案一:单进程+多线程
2.1.1设计思路
界面和任务处理线程分开,避免执行任务时界面出现卡死的情况,影响用户体验。
2.1.2详细设计
图1 单进程+多线程
1、主线程启动界面,对界面进行初始化;
2、主线程启动一个线程,作用是后台任务处理;
3、界面(主线程)和后台任务线程之间使用Queue进行数据传输,界面线程写数据,后台线程读数据;
4、后台线程的主线程是一个while循环,用于循环监听Queue;
5、用户点击界面的按钮等操作产生一个请求任务,用户每次操作界面,程序并不是直接执行任务,而是将请求任务的代码以及必要附加数据写入Queue;
6、后台线程读取到任务代码后,查询任务处理程序,将任务代码和附加数据发送给任务处理程序,任务处理完成之后,将任务处理结果emit到界面显示;
2.1.3方案有效性
1、对于轻量级的应用,即后台不存在高CPU和高内存占用的任务,此方案可以正常工作;
2.1.4方案缺陷
1、但是由于python并不是真正的多线程,所以,如果后台长期存在高CPU和高内存占用的任务,那么可能会出现界面卡死的情况;
2、另一个问题是,由于后台任务处理采用串行处理方式,如果某一个任务处理占用时间长,此时用户请求的其他任务会长时间得不到处理;
3、工具处理的任务并不全是一次性任务,而是存在长期处理任务,即后台处理线程会启动更多的常驻线程,比如trap监听任务,需要在后台启动线程进行长期监听,导致整个程序实际启动的线程数量多,影响工具的性能;
2.2方案二:多进程+多线程
2.2.1设计思路
界面和任务分离。
借用多进程解决方案一中线程的问题,
2.2.2详细设计
图1 多进程+多线程
1、主进程启动界面,对界面进行初始化;
2、主进程启动一个子进程,作用是后台任务处理;
3、进程之间使用Pipe进行数据传输,线程之间使用Queue进行数据传输,主进程和子进程各有一个Pipe和一个Queue;
4、主进程有两个线程,一个是界面主线程,一个是while循环监听线程;
5、主进程:
1)界面包含主界面和多个子界面;
2)各个界面的一个任务由任务代码和附加数据定义,用户在界面上进行操作后,程序将任务请求代码和附加数据写入Queue;
3)监听线程读取任务代码,如果任务需要本进程中的界面执行,则将任务请求代码和附加数据发送给目标界面处理,界面处理完任务之后,处理结果在两个界面中显示(按需);
4)监听线程读取任务代码,如果任务需要子进程中执行,则将任务请求代码和附加数据写入Pipe,发送给子进程;
5)监听线程从Pipe中读取任务处理结果,在界面中更新,展示给用户;
6、子进程:
1)子进程启动后,初始化所有任务处理程序;
2)子进程的主线程执行while循环监听任务;
3)监听线程读取Pipe的任务处理请求后,查询任务处理程序,将任务请求代码和附加数据发送给任务处理程序;
4)任务处理类处理完后,将处理结果写入Pipe,发送至主进程;
5)子进程中,各个任务处理程序或者功能模块如果需要其他任务处理程序执行任务,同样将任务请求代码和附加数据写入Queue,主线程将读取数据,执行任务;
2.2.3方案有效性
1、多进程真正分离了界面和任务处理,界面不会出现卡死的情况,且子进程由于没有界面的干扰,可以快速的进行任务处理;
2.2.4方案缺陷
1、并不是所有的任务都适用于放置在后台子进程,比如snmp采集任务,一是界面需要读取MIB数据库的内容并显示在界面,二是采集的大量结果需要频繁的显示在界面上。如果采用放置在子进程的方案,则进程之间通信的数据的量会非常大,且存在延时。这是我的担忧,实际上是否有问题并没有验证;
2、如果主进程界面卡死崩溃了,子进程会残留,不会随着主进程的退出而退出;
2.3方案三:多进程+多线程+看门狗
2.3.1设计思路
在方案二的基础上,加入看门狗,如果主进程异常退出了,子进程可以正常退出,解决子进程可能残留的问题。
2.3.2详细设计
图1 多进程+看门狗
1、看门狗是一个独立的线程,分为服务端和客户端;
2、主进程和子进程启动时,首先启动看门狗线程,主进程启动服务端看门狗,子进程启动客户端看门狗;
3、看门狗之间使用Pipe进行通信;
4、服务端看门狗持续监听Pipe,如果收到投喂请求,则向返回一个投喂响应;
5、客户端看门狗间隔一段时间向服务端看门狗发送一次投喂请求;
6、客户端发送投喂请求后,等待一段时间,再查询Pipe是否收到投喂响应,如果连续多次未收到投喂响应,则通知子进程退出;
7、子进程在收到退出事件后,执行退出程序;
2.3.3方案有效性
第一版的看门狗方案是借助已有的进程通信机制,由子进程的主线程定期发送投喂请求,主进程的主线程收到请求后返回投喂响应,但是此方案受其他任务处理影响很大,如果主线程执行任务耗时太长,投喂请求可能得不到及时的响应,导致子进程异常退出。因此才将看门狗在独立的线程中执行,实际效果证明该方案有效。