asyncio matplotlib show() 仍会导致程序冻结

6
我希望能够同时在模拟运行时输出其进展情况的图表。我查看了很多关于线程和多进程的示例,但它们都相当复杂。因此我认为使用Python的新的asyncio库会更容易些。
我找到了一个示例(如何在异步函数中使用'yield'?),并对其进行了修改以适应我的需求:
import matplotlib.pyplot as plt
import asyncio
import numpy as np


class DataAnalysis():
    def __init__(self):
        # asyncio so we can plot data and run simulation in parallel
        loop = asyncio.get_event_loop()
        try:
            loop.run_until_complete(self.plot_reward())
        finally:
            loop.run_until_complete(
                loop.shutdown_asyncgens())  # see: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.shutdown_asyncgens
            loop.close()

    async def async_generator(self):
        for i in range(3):
            await asyncio.sleep(.4)
            yield i * i

    async def plot_reward(self):
        # Prepare the data
        x = np.linspace(0, 10, 100)

        # Plot the data
        plt.plot(x, x, label='linear')

        #plt.show()

        # add lines to plot
        async for i in self.async_generator():
            print(i)
            # Show the plot
            plt.show()


if __name__ == '__main__':
    DataAnalysis()

问题

我添加了一个简单的plt.show(),但程序仍然会卡死。我以为用asyncio可以并行运行它?显然我的知识还不够丰富。 一个能够实现以下功能的示例将非常有帮助:

  • 每次async_generator返回一个值时,在图表(使用matplotlib)中添加一条线。
1个回答

6
首先,我误解了asyncio,它并不能让事情并行运行(使用asyncio进行并行任务)。
对于我而言似乎唯一有效的方法是plt.pause(0.001)(以非阻塞方式使用Matplotlib绘图)。 plt.draw()打开了一个窗口,但没有显示任何内容,plt.show则会冻结程序。看起来plt.show(block=False)已被弃用,并且使用plt.ion会出现问题,因为当程序完成后,最终结果会关闭。此外,使用await asyncio.sleep(0.1)无法使绘图绘制线条。
可工作代码
import matplotlib.pyplot as plt
import asyncio
import matplotlib.cbook
import warnings
warnings.filterwarnings("ignore",category=matplotlib.cbook.mplDeprecation)


class DataAnalysis():
    def __init__(self):
        # asyncio so we can plot data and run simulation in parallel
        loop = asyncio.get_event_loop()
        try:
            loop.run_until_complete(self.plot_reward())
        finally:
            loop.run_until_complete(
                loop.shutdown_asyncgens())  # see: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.shutdown_asyncgens
            loop.close()
            # keep plot window open
            plt.show()

    async def async_generator(self):
        for i in range(3):
            await asyncio.sleep(.4)
            yield i * i

    async def plot_reward(self):
        #plt.ion()  # enable interactive mode

        # receive dicts with training results
        async for i in self.async_generator():
            print(i)
            # update plot
            if i == 0:
                plt.plot([2, 3, 4])
            elif i == 1:
                plt.plot([3, 4, 5])

            #plt.draw()
            plt.pause(0.1)
            #await asyncio.sleep(0.4)


if __name__ == '__main__':
    da = DataAnalysis()

注意事项

  • 您可能会收到一条已弃用的消息:python3.6/site-packages/matplotlib/backend_bases.py:2445: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented warnings.warn(str, mplDeprecation),您可以使用warnings.filterwarnings()来抑制它。

  • 我不确定asyncio是否在我的使用情况下真正必要...

  • 对于有兴趣的人,threadingmultiprocessing之间的区别:Multiprocessing vs Threading Python


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接