首先
??今天在那边做一个UI界面的时候,想往里面做一个功能:“主线程上进行当前数据的监控、并将数据存入MongoDB中。当按下UI界面上的一个按钮后,创建一个子线程,让他去查MongoDB中的过往数据,并通过Matplotlib将其做成折线图进行数据可视化”。 ??我想这么做的理由是:我不想在我画图、展示图片的时候,我的监控停下来,所以我想把画图、展示图片的那一部分放到另一个线程里面去,这样我主线程的数据监控就不会停下来了。 ??一开始以为,这是个非常简单的事情,结果写了代码出来后发现,他爆了一个错误:
“Starting a Matplotlib GUI outside of the main thread will likely fail.”
??当时瞬间就感觉,事情不太对的样子。果然,他告诉我matplotlib只能运行在主线程里面:
“set_wakeup_fd only works in main thread”
??于是我,停止了思考(bushi ??
尝试方法1:使用multiprocessing(最后未使用)
??我开始百度,最先看到了这个方法,然后我去试了试但好像,对于我这个问题,解决不太了,效果不太好,所以就没用这个方法。当时参考的文章是这篇,感兴趣的可以自行去尝试下:https://www.it1352.com/1606767.html ??
尝试方法2:主线程中画图,然后子线程进行展示(最后未使用)
??这个思路我参考的是下面这个帖子:https://ask.csdn.net/questions/7465991 ??这个的话,我当时测过后,是没啥技术问题的,我当时根据这个方法,在点击UI界面上的按钮后,先在主线程里面使用pymongo和matplotlib库把图画好后,没有使用plt.show函数,而是变成:
plt.savefig("final.png")
??之后的话,在子线程里面,通过PIL库来进行展示即可。当时我的部分代码如下:
-----------------------------------mongo.py中(这个文件是我自己写的)-----------------------------------
from PIL import Image
import threading
def draw_final():
img=Image.open('final.png')
img.show()
class myDraw_final(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
draw_final()
def start_draw_final():
find_final()
my = myDraw_final()
my.start()
-----------------------------------我的UI界面py文件中-----------------------------------
............
............
bu1 = Button(self.window, textvariable=self.st1, font=('Arial', 10), command= \
lambda: mongo.start_draw_final())
............
............
??这样的话,是差不多可以实现我想要的效果的,现在是:子线程中显示结果,显示结果的时候,也不堵塞我主线程中的数据监测了,但是这样写还有一点缺陷,就是它绘图还是在我当前程序的主线程中进行的,当他数据读取、绘图、保存的时候,我主线程还是被堵塞了,数据监听中断了。只有显示的时候不堵塞。这样我觉得还是不太够的。
尝试方法3:欺诈(最终采用)
??正如开始的时候所说,我们的matplotlib只能在主线程中使用,那么我们的解决方法就是:就让他在主线程里面跑。 ??这个时候你可能会说:我们方法2里面,不就是在主线程里面跑的matplotlib嘛?那我们这里的方法3和方法2有什么区别呢? ??这就不对了。方法2里面,是在我们的当前UI程序的主线程里面跑的,方法3里面,我想让matplotlib觉得自己跑在主线程里,但是其实它跑在我的UI程序的子线程里。(这感觉咋和云计算里面的虚拟化一样) ??为了实现上述的效果,我把画图、显示的那一部分,写在另一个py文件,叫做draw_final.py里面,作为那个py文件的主函数。 ??然后我的UI程序里面,创造一个子线程,而这个子线程的作用,是启动draw_final.py,这样就能让matplotlib跑在它想要的主线程里面,且不影响我UI程序上数据的监测了。双赢。
??draw_final.py中的主要代码如下所示:
import matplotlib.pyplot as plt
import pymongo
def find_final():
--- 去mongodb里面查数据 ---
--- 用matplotlib画图 ---
plt.show()
if __name__ == "__main__":
find_final()
??然后是mongo.py文件,里面主要包含多线程的内容,下面为部分代码:
import threading
import os
def draw_final():
os.system("python E:\\desktop\\net9\\draw_final.py")
class myDraw_final(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
draw_final()
def start_draw_final():
my = myDraw_final()
my.start()
??UI界面上的程序中,将按钮与其绑定:
bu1 = Button(self.window, textvariable=self.st1, font=('Arial', 10), command= \
lambda: mongo.start_draw_final())
??通过上述的一轮阴险操作,成功欺骗了matplotlib,顺利实现了我们想要的结果。
总结
??希望上述的内容,能帮助遇到相同问题情况的人,谢谢大家。
|