Конфликт Python rpy2 и matplotlib при использовании многопроцессорной обработки


Я пытаюсь вычислять и генерировать графики с помощью многопроцессорной обработки. В Linux приведенный ниже код работает правильно, однако на Mac (ML) это не так, что приводит к ошибке ниже:

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

def main():
    pool = multiprocessing.Pool()
    num_figs = 2
    # generate some random numbers
    input = zip(np.random.randint(10,1000,num_figs), 
                range(num_figs))

    pool.map(plot, input)

def plot(args):
    num, i = args
    fig = plt.figure()
    data = np.random.randn(num).cumsum()
    plt.plot(data)

main()

Rpy2 - это rpy2= = 2.3.1, а R-2.13.2 (я не мог установить последнюю версию R 3.0 и rpy2 на любом mac без ошибки сегментации).

Ошибка такова:

The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().
Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.
The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().
Я перепробовал все, чтобы понять, в чем проблема, но безуспешно. Моя конфигурация такова:
Danials-MacBook-Pro:~ danialt$ brew --config
HOMEBREW_VERSION: 0.9.4
ORIGIN: https://github.com/mxcl/homebrew
HEAD: 705b5e133d8334cae66710fac1c14ed8f8713d6b
HOMEBREW_PREFIX: /usr/local
HOMEBREW_CELLAR: /usr/local/Cellar
CPU: dual-core 64-bit penryn
OS X: 10.8.3-x86_64
Xcode: 4.6.2
CLT: 4.6.0.0.1.1365549073
GCC-4.2: build 5666
LLVM-GCC: build 2336
Clang: 4.2 build 425
X11: 2.7.4 => /opt/X11
System Ruby: 1.8.7-358
Perl: /usr/bin/perl
Python: /usr/local/bin/python => /usr/local/Cellar/python/2.7.4/Frameworks/Python.framework/Versions/2.7/bin/python2.7
Ruby: /usr/bin/ruby => /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby

Любой идеи?

3 7

3 ответа:

Эта ошибка возникает в Mac OS X, когда вы выполняете операцию GUI вне основного потока, что именно то, что вы делаете, перенося свою функцию построения на многопроцессорную обработку.Пул (я предполагаю, что он не будет работать на Windows либо по той же причине - так как Windows имеет те же требования). Единственный способ, который я могу себе представить, это использовать пул для генерации данных, а затем заставить ваш основной поток ждать в цикле для данных, которые возвращаются (очередь-это способ, которым я обычно обрабатываю оно...).

Вот пример (признавая, что это может не сделать то, что вы хотите - построить все фигуры "одновременно"? - plt.show () blocks таким образом, только один рисуется одновременно, и я замечаю, что у вас нет его в вашем примере кода - но без этого я ничего не вижу на своем экране - однако, если я выну его - нет никакой блокировки и никакой ошибки, потому что все функции GUI происходят в основном потоке):

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

data_queue = multiprocessing.Queue()


def main():
    pool = multiprocessing.Pool()
    num_figs = 10

    # generate some random numbers
    input = zip(np.random.randint(10,10000,num_figs), range(num_figs))  
    pool.map(worker, input)

    figs_complete = 0
    while figs_complete < num_figs:
        data = data_queue.get()
        plt.figure()
        plt.plot(data)
        plt.show()
        figs_complete += 1

def worker(args):
    num, i = args
    data = np.random.randn(num).cumsum()
    data_queue.put(data)
    print('done ',i)

main()

Надеюсь, это поможет.

У меня была похожая проблема с моим работником, который загружал некоторые данные, создавал график и сохранял его в файл. Обратите внимание, что это немного отличается от того, что происходит в случае ОП, который, похоже, ориентирован на интерактивное построение графика. И все же я думаю, что это важно.

Упрощенная версия моего кода:

def worker(id):
    data = load_data(id)
    plot_data_to_file(data) # Generates a plot and saves it to a file.

def plot_something_parallel(ids):
    pool = multiprocessing.Pool()
    pool.map(worker, ids)

plot_something_parallel(ids=[1,2,3])

Это вызвало ту же ошибку, о которой упоминают другие:

The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().
Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.

Следуя ходу мысли @bbbruce, я решил свою проблему, переключив серверную часть matplotlib с TKAgg на неисполнение. В частности, я закомментировал следующую строку в моем файле matplotlibrc:

#backend : TkAgg

Это может быть специфично для rpy2. Есть сообщения о подобной проблеме с OS X и многопроцессорной здесь и там.

Я думаю, что использование инициализатора, который импортирует пакеты, необходимые для запуска кода в plot, может решить эту проблему (multiprocessing-doc ).