【问题标题】:Running a thread with matplotlib cause python crash使用 matplotlib 运行线程导致 python 崩溃
【发布时间】:2017-12-05 21:10:27
【问题描述】:

我的程序有 2 个非常简单的线程:

  • 一个用于监听串口
  • 一个用于文本用户界面

我还有一个matplotlib animation 在我的main() 中运行。它有一个 scope 类,这是来自 matplotlib 的示例。

当程序开始运行时,它显示了情节并且一切正常。问题是,只要用户输入一个键,程序就会崩溃,python 会以致命错误退出。

ui 线程与matplotlibscope 类无关。如果我删除创建绘图的代码,ui 线程没有问题,程序运行顺利。我还注意到我的系统上的matplotlib 使用tkinter 来创建窗口。

您对matplotlib animation 导致问题的原因有任何提示或经验吗?线程不能与matplotlib plot 一起使用吗?

我在Windows7Python 2.7 的命令行窗口中运行它。

matplotlib 版本:2.0.2 Tkinter 版本:8.5

错误:

Fatal Python error: GC object already tracked

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

或者这个错误:

TclStackFree: incorrect freePtr. Call out of sequence?

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

代码:

    import threading
import serial
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import matplotlib.animation as animation

class listner(threading.Thread):

        def __init__(self,port):
            threading.Thread.__init__(self)
            self.sport=None
            self.is_running=True
            self.init_port(port)

        def run(self):
            print ' Reading from Port'
            while self.is_running:
                try:
                    self.sport.read(1)
                except:
                    print 'Error reading port'

        def init_port(self,port):
            print '1'
            if self.sport==None or not self.sport.is_open :
                try:

                    self.sport = serial.Serial(port,115200)
                    self.sport.timeout = 1
                    self.sport.reset_input_buffer()
                    self.sport.reset_output_buffer()
                    self.port_open=True
                except:
                    print "    Port error Listener Initing\n",self.port_open,'\n',self.sport
            else:
                pass

        def process(self):
            pass


class ui(threading.Thread):

        def __init__(self):
            threading.Thread.__init__(self)     
            self.running = True

        def run(self):

            print 'Starting UI:\n'
            while self.running:
                print ' Enter input ''S'':\n'
                user = raw_input()



def main(port):

        listner_thread = None
        try:
            listner_thread = listner(port)
            listner_thread.start();
        except:
            print "Listener Thread Failed To Start"
            return

        ui_thread=None
        try:
            ui_thread = ui()
            ui_thread.start()          
        except:
            print "UI Thread Failed To Start"
            return

        run_charts()



def run_charts():
        fig, (ax1, ax2) = plt.subplots(2, 1)

        scope1 = Scope(ax1)
        ani1 = animation.FuncAnimation(fig, scope1.update, emit_ch1, interval=10,blit=True)

        scope2 = Scope(ax2)
        ani2 = animation.FuncAnimation(fig, scope2.update, emit_ch2, interval=10,blit=True)

        plt.show()

def emit_ch1():
    yield 0.001

def emit_ch2():
    yield -0.001

class Scope(object):
        def __init__(self, ax, maxt=2, dt=0.02):
            self.ax = ax
            self.dt = dt
            self.maxt = maxt
            self.tdata = [0]
            self.ydata = [0]
            self.line = Line2D(self.tdata, self.ydata)
            self.ax.add_line(self.line)
            self.ax.set_ylim(-.009, 0.009)
            self.ax.set_xlim(0, self.maxt)

        def update(self, y):
            t = self.tdata[-1] + self.dt
            self.tdata.append(t)
            self.ydata.append(y)
            self.line.set_data(self.tdata, self.ydata)
            return self.line,



if __name__ == '__main__':
        main('COM11')

【问题讨论】:

  • 如果您提供一个仍然存在此问题的更小示例,人们可能更容易调试此问题。见stackoverflow.com/help/mcve
  • 当我将此代码放入 python 中时,我收到错误:AttributeError: type object 'listner' has no attribute 'listner' 因为这一行:listner_thread = listner.listner(port) 您确定您提供的代码是在用户按下键之前有效的代码吗?
  • 我更新了代码。这完全有效并重现了问题。

标签: python multithreading matplotlib tkinter


【解决方案1】:

第一个错误“Fatal Python Error:GC object Already Tracked”于 2013 年以“CLOSED WONTFIX”状态关闭,请参阅 Bugzilla 上的 bug report

似乎在 2015 年 [关于 dask] 再次提出时的临时修复是使用此代码use a single thread

   import dask
   dask.set_options(get=dask.async.get_sync)

但问题实际上在于dataframe.read_csv 问题。

问题是在更高版本的熊猫中eventually solved。如果你升级你的 matplotlib 版本,这个问题很可能也可以通过类似的修复来解决。

希望对你有帮助

【讨论】:

  • 感谢您的信息。我猜Tkinter 有问题。我在另一台使用MPL WebAgg GUI 框架的机器上运行了相同的代码,它运行顺利。它会在浏览器中打开图表,但这是不可取的。
  • @dandikain 在导入 pyplot 之前插入此行 'matplotlib.use('Agg')' 以避免打开窗口 - Source 也建议在 show() 之前保存图表,例如plt.savefig('fig')
  • 根据上面的代码应该是第4行,然后导入pyplot。 (而不是将线放在一开始)。你试过了吗?
  • @dandikain 你能不能调试你的代码来找到它第一次被导入的地方(显然它已经在这段代码之前被导入)......并在那里插入行?除此之外,我没有建议。希望你解决问题。很高兴它已部分解决。
猜你喜欢
  • 2013-10-27
  • 1970-01-01
  • 2012-12-19
  • 2018-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-28
相关资源
最近更新 更多