Matplotlib - 多进程



多进程是一种用于并发执行多个进程的技术,利用多核处理器。在 Python 中,multiprocessing 模块提供了一种方便的方式来创建和管理并行进程。这对于可以并行化的任务很有用,例如生成绘图、运行模拟或对大型数据集执行计算。

Matplotlib 中的多进程

Matplotlib 传统上以单线程方式使用,将其与 multiprocessing 库结合使用可以并行创建绘图。这在处理大量绘图或计算密集型任务时很有用。

创建多个 Matplotlib 绘图

顺序创建多个绘图会导致执行速度变慢,尤其是在处理大量绘图时。在这种情况下,使用多进程技术可以通过允许并发创建多个绘图来显著提高性能。

示例

让我们来看一个基本示例,演示如何使用多进程并行创建多个 Matplotlib 绘图。

import matplotlib.pyplot as plt
import numpy as np
import multiprocessing

def plot(datax, datay, name):
   x = datax
   y = datay**2
   plt.scatter(x, y, label=name)
   plt.legend()
   plt.show()

def multiP():
   for i in range(4):
      p = multiprocessing.Process(target=plot, args=(i, i, i))
      p.start()

if __name__ == "__main__": 
   input('Press Enter to start parallel plotting...') 
   multiP()

输出

执行上述程序后,将并行创建 4 个 matplotlib 绘图,请参阅下面的视频以供参考 -

multiprocessing_ex1

保存多个 Matplotlib 图形

并发保存多个 Matplotlib 图形是多进程可以发挥优势的另一种场景。

示例 1

这是一个使用多进程并发保存多个 Matplotlib 图形的示例。

import matplotlib.pyplot as plt
import numpy.random as random
from multiprocessing import Pool

def do_plot(number):
   fig = plt.figure(number)

   a = random.sample(1000)
   b = random.sample(1000)

   # generate random data
   plt.scatter(a, b)

   plt.savefig("%03d.jpg" % (number,))
   plt.close()

   print(f"Image {number} saved successfully...")

if __name__ == '__main__':
   pool = Pool()
   pool.map(do_plot, range(1, 5))

输出

执行上述代码后,我们将获得以下输出 -

Image 1 saved successfully...
Image 2 saved successfully...
Image 3 saved successfully...
Image 4 saved successfully...

如果导航到保存绘图的目录,您将能够观察到 ved 001.jpg、002.jpg、003.jpg 和 004.jpg 图像,如下所示 -

multiprocessing_ex2

示例 2

这是一个演示如何使用多进程在一个进程中生成数据并在另一个进程中使用 Matplotlib 绘制数据的示例。

import multiprocessing as mp
import time
import matplotlib.pyplot as plt
import numpy as np

# Fixing random state for reproducibility
np.random.seed(19680801)

class ProcessPlotter:
   def __init__(self):
      self.x = []
      self.y = []

   def terminate(self):
      plt.close('all')

   def call_back(self):
      while self.pipe.poll():
         command = self.pipe.recv()
         if command is None:
            self.terminate()
            return False
         else:
            self.x.append(command[0])
            self.y.append(command[1])
            self.ax.plot(self.x, self.y, 'ro')
      self.fig.canvas.draw()
      return True

   def __call__(self, pipe):
      print('Starting plotter...')
      self.pipe = pipe
      self.fig, self.ax = plt.subplots()
      timer = self.fig.canvas.new_timer(interval=1000)
      timer.add_callback(self.call_back)
      timer.start()
      print('...done')
      plt.show()

class NBPlot:
   def __init__(self):
      self.plot_pipe, plotter_pipe = mp.Pipe()
      self.plotter = ProcessPlotter()
      self.plot_process = mp.Process(
         target=self.plotter, args=(plotter_pipe,), daemon=True)
      self.plot_process.start()

   def plot(self, finished=False):
      send = self.plot_pipe.send
      if finished:
         send(None)
      else:
         data = np.random.random(2)
         send(data)

# Main function for the integrated code
def main_with_multiprocessing():
   pl = NBPlot()
   for _ in range(10):
      pl.plot()
      time.sleep(0.5)
   pl.plot(finished=True)

if __name__ == '__main__':
   if plt.get_backend() == "MacOSX":
      mp.set_start_method("forkserver")
   input('Press Enter to start integrated example...') 
   main_with_multiprocessing()

输出

执行上述程序后,将使用随机数据生成 matplotlib 绘图,请参阅下面的视频以供参考 -

multiprocessing_ex3 GIF
广告