今天在那边做一个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()
# UI界面上进行绑定的函数
def start_draw_final():
	# find_final函数就是使用matplotlib、pymongo进行数据读取、画图、存储的函数
	find_final()  # 它会把最终结果以“final.png”的形式存储到本地
	# 但上面那个函数执行的地方,并不是子线程中,而是在主线程中
	# 下面的my.start中执行的,才是在子线程里执行的命令
    my = myDraw_final()
    my.start()
-----------------------------------我的UI界面py文件中-----------------------------------
# 该按钮点击后,执行mongo.py下的start_draw_final函数
............
............
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
# 对ori数据进行查询
def find_final():
	--- 去mongodb里面查数据 ---
	--- 用matplotlib画图 ---
	plt.show()
if __name__ == "__main__":
	find_final()

  然后是mongo.py文件,里面主要包含多线程的内容,下面为部分代码:

import threading
import os
# 调用上面画图的那个draw_final.py程序
def draw_final():
    os.system("python E:\\desktop\\net9\\draw_final.py")
# 多线程,多出来的一条线程用于调用另一个程序
class myDraw_final(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
	# 子线程用来调用那个py文件,此时,那个被调用的py文件中的程序运行在那个py文件的主线程里
	# 但是那个程序,是在我这个程序的子线程里被调用的
    def run(self):
        draw_final()
# UI窗口上的按钮与这个函数进行绑定,那个按钮按下后,创建子线程并开始执行上面那个类的run函数
def start_draw_final():
    my = myDraw_final()
    my.start()

  UI界面上的程序中,将按钮与其绑定:

# 按下按钮后,跑去执行mongo.py中的start_draw_final函数
bu1 = Button(self.window, textvariable=self.st1, font=('Arial', 10), command= \
            lambda: mongo.start_draw_final())

  通过上述的一轮阴险操作,成功欺骗了matplotlib,顺利实现了我们想要的结果。

  希望上述的内容,能帮助遇到相同问题情况的人,谢谢大家。

※练习使用面向对象的思维设计并编写程序 9、项目实战一、模拟人生游戏 ※设定两个故事场景,场景可以穿插衔接,人物之间有关系和互动并且互相影响,根据 不同用户的玩法实现开放式结局 1、Socket 介绍 2、Python socket 语法 3、简单的socket 交互程序 4、Socket Server的开发与使用 5、多线程非阻塞并发自处理 6、练习程序:用SOCKET模拟实现SSH客户端功能 6、项目实战二、开发FTP服务器\客户端软件 ※分别开发服务器端和客户端,通过Socket模块实现网络通信,模拟实现FTP主要的文件下载、上传功能、实现多用户并发在线使用。 1、 项目实战三、开发运维审计服务器,实现公司全网用户操作审计需求 ※开发一个堡垒机,实现用户可以通过WEB 和命令行登录到所有LINUX服务器上,纪录所有用户命令操作 2、项目实战四、通过Python脚本连接MYSQL数据库实现数据自动入库、更新 3、项目实战五、开发C/S架构备份服务器,实现远程备份 ※使用PYTHON SOCKET模块实现文件的远程压缩传输 二、Python高级课程列表 1、Python 多线程程序开发使用 2、项目实战七、开发实现对上千台服务器的批量管理,分发指令、文件传送的运维管理程序 ※用多线程的方式并发连接登录多台LINUX服务器,实现并发命令操作、文件分发,实时结果返回,并可根据服务器性能控制线程量,千台机器改密码1分钟完成。 3、HTML/JAVAScript基础 4、WEB JS Package BootStrap 介绍与使用 ※通过BootsStrap 样式制作精美清新的WEB页面 5、使用JSON(实现不同程序间内存数据交换) 6、JQuery/Ajax 基础与使用 ※实现页面部分内容与后台交互并实时刷新页面 1、Python WEB 架构Django的介绍、使用 2、Django manage.py 3、Django 视图 4、Django models使用Mysql数据库 5、Django 模板 6、Django url 7、Django Admin 8、编写前后台动态交互页面 三、企业项目实战(web及运维软件开发) matplotlib是基于Python语言的开源项目,旨在为Python提供一个数据绘图包。在使用Python matplotlib库绘制数据图时,需要使用图例标注数据类别,但是传参时,会出现图例解释文字只显示第一个字符,需要在传参时在参数后加一个逗号(应该是python语法,加逗号,才可以把参数理解为元组类型吧),就可解决这个问题, import numpy as np import matplotlib.pyplot as plt from matplotlib.ticker import MultipleLocator from pylab import mpl matplotlib是运行在一个子线程的,出现了如下警告:`UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail.`无法使用`matplotlib.backends.backend_qt5agg` 下的 `FigureCanvasQTAgg`直接把图像绘制在UI窗口 Flask项目实战使用matplotlib出现报错:set_wakeup_fd only works in main thread of the main interpreter,已解决。 多线程采用import threading库。 2.可能原因: 引入的 import matplotlib.pyplot as plt 是个全局变量,应该就是它引起的线程不安全。 3.解决办法: 觉得线程不安全,那就加锁 from threading import Lock, RLock lock = Lock() rlock = RLock() 有些情况下,我们面对实时更新的数据,希望能够在一个窗口可视化出来,并且能够实时更新,方便我们观察数据的变化,从而进行数据分析,例如:绘制音频的波形,绘制动态曲线等,下面介绍使用matplotlib结合多线程绘制动态图,希望能帮助到有需要的朋友。 本人遇到的场景:最近刚好在学习人工智能的遗传算法,并且使用该算法求解TSP,了解这个算法的朋友知道这个算法是通过不断迭代,寻找适应度大的最优解,为了了解迭代过程适应度的变化,我希望能够实时更新迭代过程的适应度,将其可视化出来(数据量不断增大) 在threading.Thread创建的线程使用matplotlib.pyplot来做图,但出现: UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail 之后查找Matplotlib官方文档,有这样的描述: Working with threads: Matplotlib is not thread-safe: in fact, there ar. 【python 报错解决方法】ValueError: set_wakeup_fd only works in main thread 将python的版本从3.7.3换成了3.10.8 在本项目,我们使用了 `threading` 库创建了一个新线程,在该线程绘制跨年烟花。我们使用 `matplotlib` 库的 `scatter` 函数绘制跨年烟花,并使用 `plt.pause` 函数暂停一段时间,再使用 `clear` 函数清除图像。在上述代码,我们在每次循环绘制了 5 个跨年烟花。您可以根据自己的需要调整这个数字,使烟花的数量更多。如果希望让烟花放的更多,可以在绘制跨年烟花的函数。python多线程绘制跨年烟花。效果发现不理想,烟花太稀疏。 /home/ubuntu/.virtualenvs/da/lib/python3.6/site-packages/matplotlib/font_manager.py:1238: UserWarning: findfont: Font family [‘sans-serif’] not found. Falling back to DejaVu Sans. (prop.get_family(), self.defaultFamily[fontext])) 原创文章 90获赞 117访问量 19万+