Вызов matplotlib ПОСЛЕ многопроцессорной обработки иногда приводит к ошибке: основной поток не находится в основном цикле - PullRequest
0 голосов
/ 29 октября 2018

Я делаю некоторую многопроцессорность, и мне хотелось бы понять, почему иногда (но никогда на первой итерации цикла) генерируется следующий фрагмент кода следующая ошибка:

   Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7f6c40d25ba8>>
    Traceback (most recent call last):
      File "/usr/lib/python3.5/tkinter/__init__.py", line 3359, in __del__
        self.tk.call('image', 'delete', self.name)
    RuntimeError: main thread is not in main loop
    Tcl_AsyncDelete: async handler deleted by the wrong thread
    Traceback (most recent call last):
      File "Analize0.py", line 94, in <module>
        Lambda = np.array(Rescal.multiprocess_loop_grouped(grouped_spatial_lambda, range(Nalti), Group_size, N_thread, *args))
      File "/home/gadal/PythonLib_perso/Rescal/Lib_Rescal.py", line 135, in multiprocess_loop_grouped
        return [dic[i] for i in sorted(dic.keys())]
      File "/home/gadal/PythonLib_perso/Rescal/Lib_Rescal.py", line 135, in <listcomp>
        return [dic[i] for i in sorted(dic.keys())]
      File "<string>", line 2, in __getitem__
      File "/usr/lib/python3.5/multiprocessing/managers.py", line 717, in _callmethod
        kind, result = conn.recv()
      File "/usr/lib/python3.5/multiprocessing/connection.py", line 250, in recv
        buf = self._recv_bytes()
      File "/usr/lib/python3.5/multiprocessing/connection.py", line 407, in _recv_bytes
        buf = self._recv(4)
      File "/usr/lib/python3.5/multiprocessing/connection.py", line 383, in _recv
        raise EOFError
    EOFError

Вот код:

list_per = sorted(glob.glob('Plage*'))
Nper = len(list_per)
for simul_per in list_per :
    print(simul_per)
    path_small = os.getcwd()
    os.chdir(simul_per)
    list_alti = sorted(glob.glob('ALTI00*'))
    Nalti = len(list_alti)
    Group_size = Nalti // N_thread

    print('Reading files ...')
    Map = np.array(Rescal.multiprocess_loop_grouped(Rescal.read_file, list_alti, Group_size, N_thread))

    print('Processing data ...')

    ##################################################################################### Data analysis
    Y_simul = (100, 500)
    Deviation = np.empty((Nalti,Y_simul[1] - Y_simul[0], Map.shape[-1]))
    for i in range(Nalti):  ############### removing average beach topography
        Deviation[i,:,:] = Map[i,Y_simul[0]:Y_simul[1],:] - np.mean(Map[i,Y_simul[0]:Y_simul[1],:], axis = 0, keepdims = True)



    ############   Beach wavelength
    print('     Beach wavelength ...')

    X_beach = (300,650)

    args = [X_beach, Deviation]
    Temp = Rescal.multiprocess_loop_grouped(find_lambda_plage, range(Nalti), Group_size, N_thread, *args)
    Lambda_plage = np.array([i[0] for i in Temp])
    Orientation = np.array([i[1] for i in Temp])

    ############ Wavelength as a function of space
    print('     Wavelength as a function of space ...')

    args = [Deviation]
    Lambda = np.array(Rescal.multiprocess_loop_grouped(grouped_spatial_lambda, range(Nalti), Group_size, N_thread, *args))

    print('Saving data ...')

    Data = {}
    Data['Lambda_finger'] = Lambda_finger
    Data['Lambda_plage'] = Lambda_plage
    Data['Orientation'] = Orientation
    Data['Map'] = Map
    Data['Lambda'] = Lambda

    np.save('Data', Data)

    print('Saving figures ...')

    plt.figure()
    plt.plot(Lambda_finger)
    plt.ylim([0, 300])
    plt.savefig('Lambda_finger.pdf')

    plt.clf()
    plt.plot(Lambda_plage)
    plt.plot(Lambda_finger[:,10])
    plt.ylim([0, 300])
    plt.legend(('Lambda plage', 'Lambda finger'))
    plt.savefig('Lambda.pdf')

    plt.clf()
    plt.imshow(Lambda)
    cbar = plt.colorbar()
    plt.xlabel('x')
    plt.ylabel('Time')
    cbar.set_label('Lambda')
    plt.clim([0, 80])
    plt.savefig('Spatial_time_lambda.pdf')


    plt.close('all')

    os.chdir(path_small)

Я выполняю несколько независимых задач над файлами, которые у меня есть, используя функцию, которую я написал, и которая описана здесь: Функция, которая обрабатывает другую функцию .

Однако функции, вызываемые той, которая их обрабатывает, никогда не вызывают matplotlib, который вызывается основным потоком после того, как последний вызов многопроцессорной обработки выполнен.

Например, функция из предыдущей ошибки grouped_spatial_lambda состоит из:

def spatial_evolution_lambda(Map):
    Lambda = []
    for x in range(Map.shape[1]):
        Lambda.append(Anls.find_first_max(autocorr(Map[:,x])))
    return Lambda

def grouped_spatial_lambda(indexes,dic,Deviation):
    for i in indexes:
        dic[i] = spatial_evolution_lambda(Deviation[i,:,:])

def find_first_max(a, valmax = False):
    inds = find_peaks(a)[0]
    if len(inds) > 0:
        l = inds[inds > 5]
        if len(l) > 0:
            testerr = 0
            a_norm = a/np.max(a)
            x_fit = np.array([i for i in range(int(l[0]/2), int(3*l[0]/2))])
            x_fit = x_fit[x_fit < len(a)]
            y_fit = a_norm[x_fit]
            x_fit = x_fit[y_fit > 0]
            y_fit = a_norm[x_fit]
            if x_fit.size == 0 or len(x_fit) < 3 :
                lamb = np.nan
                amp = np.nan
            else:
                try:
    #                popt, pcov = curve_fit(gaus,x_fit.ravel(),y_fit.ravel(), p0=[np.max(y_fit),np.mean(x_fit),np.mean(x_fit)])
                    popt, pcov = curve_fit(gaus,x_fit,y_fit, p0=[np.max(y_fit),np.mean(x_fit),np.mean(x_fit)])

                except RuntimeError:
                    lamb =  np.nan
                    amp = np.nan
                    testerr = 1
                if testerr == 0:
                    lamb =  popt[1]
                    amp = popt[0]
        else:
            lamb = np.nan
            amp = np.nan
    else:
        lamb =  np.nan
        amp = np.nan
    if valmax == False:
        return lamb
    else:
        return lamb, amp, 1.96/np.sqrt(a.size)

Из того, что я понимаю из опубликованной ошибки, tkinter генерирует исключение, которое приводит к ошибке EOF? Как это может быть, поскольку вызов matplotlib выполняется после многопроцессорной обработки других функций? Это как-то связано с циклом? (Предыдущий звонок в matplotlib ..?) Как заставить matplotlib работать в основном потоке?

...