Советы по оптимизации для полностью автоматизированного, параллельного по времени построения графиков данных из N-мерных наборов данных - PullRequest
0 голосов
/ 03 апреля 2019

Задание : получение графиков (обычно комбинация заполненных / незаполненных контуров) некоторых переменных, содержащихся в наборе данных, полученных с помощью численных моделей прогнозирования погоды.Это необходимо автоматизировать, так как новые данные загружаются каждые 6 часов (приблизительно), а новые графики создаются и загружаются на FTP для визуализации как можно скорее.

Мое решение и моя проблема : скрипт драйвера, который заботится о загрузке и подготовке файлов, записан в bash по соображениям скорости.Поскольку на сервере данные разбиты на отдельные файлы, содержащие один момент времени и один уровень, эта фаза распараллеливается с использованием (gnu) parallel.Этот этап довольно быстрый и оптимизированный.Однако следующий этап, который включает в себя построение данных с использованием python и главным образом matplotlib.pyplot, по-прежнему самый длинный и требует много памяти.

Анатомия сценария построения У меня есть 2 секции, функция main, где вся предварительная обработка входных файлов выполняется только один раз, чтобы использовать как можно меньше памяти и вычислений, и функция plot_files, которая отображает только данные.

import xarray as xr 
from multiprocessing import Pool
from functools import partial

def main():
    file = glob(input_file)
    dset = xr.open_dataset(file[0])

    # Do some pre-processing and get the variables/coordinates
    # from the file
    var = dset.var

Затем функция main охватывает несколько экземпляров функции построения графика с использованием multiprocessing.Здесь экземпляр фигуры matplotlib вместе с проекцией basemap создаются таким образом, что это выполняется только один раз: функция построения графика позаботится о добавлении элементов в график и удалит их на каждом временном шаге для следующей итерации.

    fig = plt.figure()
    ax  = plt.gca()
    m, x, y = get_projection(lon2d, lat2d, projection)

    # All the arguments that need to be passed to the plotting function
    args = dict(m=m, x=x, y=y, ax=ax,
                  var=var, time=time, projection=projection)

    # Parallelize the plotting by dividing into chunks and processes 
    dates = chunks(time, chunks_size)
    plot_files_param = partial(plot_files, **args)
    p = Pool(processes)
    p.map(plot_files_param, dates)

Распараллеливание во времени выглядело естественным, так как вы должны создать один и тот же график за многократный шаг, но данные уже есть, и вы сможете их использовать!

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

def plot_files(dates, **args):
    for date in dates:
        # Find index in the original array to subset when plotting
        i = np.argmin(np.abs(date - args['time'])) 
        cs = args['ax'].contourf(args['x'], args['y'], args['var'][i])

        plt.savefig(filename, **options_savefig)        

        remove_collections([cs])

remove_collections заботится об удалении любого элемента (это могут быть контурные линии, метки, аннотации ...).

В настоящее время у меня работает скрипт для каждого разного типа графика, который я делаю, в то время как все общие функции импортируются из модуля utils.py.

Я уверен, что это не самая умная реализация параллельной прорисовки.Недостатки, которые я вижу сейчас, - это использование памяти, которое может быть уменьшено путем передачи в plot_files функции массива только на определенном временном шаге, но я не уверен, что можно распараллелить с multiprocessing через переменное измерение.

У кого-нибудь есть совет по улучшению моего кода?Я попытался свести примеры к ядру, но, конечно, есть еще много деталей.Один из проектов, включающих этот скрипт, можно посмотреть здесь https://github.com/guidocioni/icon_forecasts

...