>

멀티 프로세싱 모듈로 많은 수치에서 matplotlib.savefig () 속도를 높이고 병렬과 시퀀스 간의 성능을 벤치마킹하려고합니다.

코드는 다음과 같습니다 :

# -*- coding: utf-8 -*-
"""
Compare the time of matplotlib savefig() in parallel and sequence
"""
import numpy as np
import matplotlib.pyplot as plt
import multiprocessing
import time

def gen_fig_list(n):
    ''' generate a list to contain n demo scatter figure object '''
    plt.ioff()
    fig_list = []
    for i in range(n):
        plt.figure();
        dt = np.random.randn(5, 4);
        fig = plt.scatter(dt[:,0], dt[:,1], s=abs(dt[:,2]*1000), c=abs(dt[:,3]*100)).get_figure()
        fig.FM_figname = "img"+str(i)
        fig_list.append(fig)
    plt.ion()
    return fig_list

def savefig_worker(fig, img_type, folder):
    file_name = folder+"\\"+fig.FM_figname+"."+img_type
    fig.savefig(file_name, format=img_type, dpi=fig.dpi)
    return file_name

def parallel_savefig(fig_list, folder):
    proclist = []
    for fig in fig_list:
        print fig.FM_figname,
        p = multiprocessing.Process(target=savefig_worker, args=(fig, 'png', folder)) # cause error
        proclist.append(p)
        p.start()
    for i in proclist:
        i.join()

if __name__ == '__main__':
    folder_1, folder_2 = 'Z:\\A1', 'Z:\\A2'
    fig_list = gen_fig_list(10)
    t1 = time.time()
    parallel_savefig(fig_list,folder_1)
    t2 = time.time()
    print '\nMulprocessing time    : %0.3f'%((t2-t1))
    t3 = time.time()
    for fig in fig_list:
        savefig_worker(fig, 'png', folder_2)
    t4 = time.time()
    print 'Non_Mulprocessing time: %0.3f'%((t4-t3))

그리고 나는 문제 "This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information." 를 만나   p = multiprocessing.Process(target=savefig_worker, args=(fig, 'png', folder)) 로 인한 오류  .

왜? 그리고 그것을 해결하는 방법?

(Windows XP + Python : 2.6.1 + Numpy : 1.6.2 + Matplotlib : 1.2.0)

수정 : (python 2.7.3에서 오류 메시지 추가)

python 2.7.3의 IDLE에서 실행될 때 아래와 같은 오류 메시지가 나타납니다 :

>>> 
img0
Traceback (most recent call last):
  File "C:\Documents and Settings\Administrator\desktop\mulsavefig_pilot.py", line 61, in <module>
    proc.start()
  File "d:\Python27\lib\multiprocessing\process.py", line 130, in start
  File "d:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "d:\Python27\lib\pickle.py", line 748, in save_global
    (obj, module, name))
PicklingError: Can't pickle <function notify_axes_change at 0x029F5030>: it's not found as matplotlib.backends.backend_qt4.notify_axes_change

수정 : (내 솔루션 데모)

에서 영감을 받음 Matplotlib : 여러 스레드에서 동시 플로팅

# -*- coding: utf-8 -*-
"""
Compare the time of matplotlib savefig() in parallel and sequence
"""
import numpy as np
import matplotlib.pyplot as plt
import multiprocessing
import time

def gen_data(fig_qty, bubble_qty):
    ''' generate data for fig drawing '''
    dt = np.random.randn(fig_qty, bubble_qty, 4)
    return dt

def parallel_savefig(draw_data, folder):
    ''' prepare data and pass to worker '''
    pool = multiprocessing.Pool()
    fig_qty = len(draw_data)
    fig_para = zip(range(fig_qty), draw_data, [folder]*fig_qty)
    pool.map(fig_draw_save_worker, fig_para)
    return None

def fig_draw_save_worker(args):
    seq, dt, folder = args
    plt.figure()
    fig = plt.scatter(dt[:,0], dt[:,1], s=abs(dt[:,2]*1000), c=abs(dt[:,3]*100), alpha=0.7).get_figure()
    plt.title('Plot of a scatter of %i' % seq)
    fig.savefig(folder+"\\"+'fig_%02i.png' % seq)
    plt.close()
    return None

if __name__ == '__main__':
    folder_1, folder_2 = 'A1', 'A2'
    fig_qty, bubble_qty =  500, 100
    draw_data = gen_data(fig_qty, bubble_qty)
    print 'Mulprocessing  ...   ',
    t1 = time.time()
    parallel_savefig(draw_data, folder_1)
    t2 = time.time()
    print 'Time : %0.3f'%((t2-t1))
    print 'Non_Mulprocessing .. ', 
    t3 = time.time()
    for para in zip(range(fig_qty), draw_data, [folder_2]*fig_qty):
        fig_draw_save_worker(para)
    t4 = time.time()
    print 'Time : %0.3f'%((t4-t3))
    print 'Speed Up: %0.1fx'%(((t4-t3)/(t2-t1)))

  • 답변 # 1

    실제로는 버그가 아니고 더 많은 한계가 있습니다.

    설명은 오류 메시지의 마지막 줄에 있습니다 :

    PicklingError: Can't pickle <function notify_axes_change at 0x029F5030>: it's not found as matplotlib.backends.backend_qt4.notify_axes_change
    
    

    그림 개체의 요소를 피클 할 수 없다는 것을 알려줍니다.  프로세스간에 데이터를 전달합니다. 주요 프로세스에서 객체를 피클하고 피클로 선적 한 다음 반대편에서 재구성합니다.정확한 문제를 고치더라도 (다른 백엔드를 사용하거나 문제를 일으킬 수있는 문제가있는 기능을 제거하여) 다른 방식으로 문제가 발생할 수 있음) MultiProcess 의 핵심 부분이 있다고 확신합니다 Figure 또는 Axes  절일 수없는 물건

    @bigbug가 지적한 바와 같이, Matplotlib :이 한계를 극복하는 방법의 예는 여러 스레드에서 동시 플로팅입니다. 기본 아이디어는전체플로팅 루틴을 하위 프로세스로 푸시하여 Canvas 만 푸시하는 것입니다.  프로세스 경계에 걸쳐 일부 구성 정보를 배열 할 수 있습니다.

  • 답변 # 2

    matplotlib 코드 (가져 오기 포함)를 함수로 이동할 수 있습니다.

    <올>

    코드 상단에 matplotlib 가져 오기 또는 matplotlib.pyplot을 plt로 가져 오지 않았는지 확인하십시오.

    가져 오기를 포함한 모든 matplotlib를 수행하는 함수를 만듭니다.

    예 :

    numpy
    
    

    import numpy as np from multiprocessing import pool def graphing_function(graph_data): import matplotlib.pyplot as plt plt.figure() plt.hist(graph_data.data) plt.savefig(graph_data.filename) plt.close() return pool = Pool(4) pool.map(graphing_function, data_list)

관련 자료

  • 이전 문자열에서 문자를 바꾸는 효율적인 방법 (java)?
  • 다음 java - 최신 버전의 Jetty (910RC2) 및 Jersey (27)에서 작동하도록 예제를 어떻게 업데이트합니까?