死锁这个东西原本只是在课本上见过,没想到今天在修改服务端的代码时就碰上了。
起因是因为在实现一个日志查询功能时,后端的接口太少而且设计得不太合理,php前端就需要多次访问db,查询出所有的信息,信息之间有依赖关系,所以.ajax关了异步,这样在页面查询时能明显感觉到延迟,一开始我试着把展示的条目减少,希望以此来提示体验,后来终究觉得这种投机的方法治标不治本,而且还是能感受到延迟,所以决定还是动一下服务端的代码,新增一个接口以更适应于业务的查询。一开始新增好相应的接口后在浏览器访问,出现很奇怪的错误,PHP报socket出错的提示,之前遇到过类似的,我觉得应该是服务端返回结果超时的问题,可是并不知道为何会超时,单纯的db查询应该不至于这么慢才对,于是打log,断点调试,看了好久看不出是什么原因……无奈之中不断滚动鼠标大致浏览下代码的逻辑,看到锁的初始化的相关东西,在想会不会是因为出现了死锁?服务端的代码里每个访问到db的函数在一开始都直接加了域锁,其定义如下:
(也是全局的锁,mutex在main函数文件里定义为全局),所以每个函数不能直接调用另一个函数了,要么在调用前解锁,要么在调用前不加锁,可是这个域锁是直接在构造时上锁析构时解锁的,无法手动进行加解锁的操作,我试着改了下这个类的结构,加上能够手动加解锁的方法,但感觉改之后会带来更复杂的逻辑,毕竟用到这个锁的地方还是挺多的,所以还是尝试在db查询的函数里移动下锁的位置吧,把它的初始化和sql语句的真正执行位置用dowhile(0)包裹起来:
这样子这个域锁就能及时析构解锁,不会影响到其它的函数里的sql查询了,运行后终于得到了预期的效果,不会死锁,浏览器页面的查询耗时确实快了好几倍,毕竟这是直接在服务端进行多次的db查询而不是由客户端发起,相比起来IO的耗时是一样的(db查询的逻辑是相同的),减少的是数据在网络上传输的耗时,浏览器一次查询即可得到最终的数据,不用像修改之前那样与服务端进行多次的交互,浪费了数据在网络上来回的不必要的耗时。(或许还有PHP与c++处理数据时的耗时差别,不过感觉应该不是最关键的?没做过完整的测试,问题解决了也不想过多纠结了)其实服务端的代码还是有不少写得不合理的地方,例如某个东西应该用到的时候才初始化,不需要时就及时把它占有的资源释放掉。不然会给后续维护的人带来很多很难调试的bug。
北京治疗白癜风哪家技术好北京治疗白癜风的最佳医院