Как я могу распараллелить эту функцию подсчета слов? - PullRequest
4 голосов
/ 05 ноября 2011

У меня есть некоторый последовательный код, подобный этому, который вычисляет совпадения слов, то есть подсчитывает парные слова.Следующая программа работает, за исключением того, что список предложений составлен для иллюстративных целей.

import sys
from collections import defaultdict

GLOBAL_CONCORDANCE = defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: [])))

def BuildConcordance(sentences):
    global GLOBAL_CONCORDANCE
    for sentenceIndex, sentence in enumerate(sentences):
        words = [word for word in sentence.split()]

        for index, word in enumerate(words):
            for i, collocate in enumerate(words[index:len(words)]):
                GLOBAL_CONCORDANCE[word][collocate][i].append(sentenceIndex)

def main():
    sentences = ["Sentence 1", "Sentence 2", "Sentence 3", "Sentence 4"]
    BuildConcordance(sentences)
    print GLOBAL_CONCORDANCE

if __name__ == "__main__":
    main()

Для меня первый цикл for можно распараллелить, потому что вычисляемые числа являются независимыми.Однако изменяемая структура данных является глобальной.

Я пытался использовать модуль Python Pool, но у меня возникли некоторые проблемы с травлением, которые заставляют меня задуматься, использую ли я правильный шаблон проектирования.Может кто-нибудь предложить хороший способ распараллеливания этого кода?

Ответы [ 3 ]

1 голос
/ 05 ноября 2011

В общем случае многопроцессорная обработка проще всего при использовании функционального стиля.В этом случае мое предложение будет возвращать список кортежей результатов из каждого экземпляра рабочей функции.Дополнительная сложность вложенных defaultdict s на самом деле ничего не дает.Примерно так:

import sys
from collections import defaultdict
from multiprocessing import Pool, Queue
import re

GLOBAL_CONCORDANCE = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))

def concordance_worker(index_sentence):
    sent_index, sentence = index_sentence
    words = sentence.split()

    return [(word, colo_word, colo_index, sent_index)
            for i, word in enumerate(words)
            for colo_index, colo_word in enumerate(words[i:])]

def build_concordance(sentences):
    global GLOBAL_CONCORDANCE
    pool = Pool(8)

    results = pool.map(concordance_worker, enumerate(sentences))

    for result in results:
        for word, colo_word, colo_index, sent_index in result:
            GLOBAL_CONCORDANCE[word][colo_word][colo_index].append(sent_index)

    print len(GLOBAL_CONCORDANCE)


def main():
    sentences = ["Sentence 1", "Sentence 2", "Sentence 3", "Sentence 4"]
    build_concordance(sentences)

if __name__ == "__main__":
    main()

Дайте мне знать, если это не создаст то, что вы ищете.

1 голос
/ 05 ноября 2011

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

Используемая вами структура данных не очень эффективна с точки зрения использования памяти, поскольку словари Python имеют большие накладные расходы памяти, и вы создаете lot из них. Кроме того, вы добавляете очень большое количество элементов в «соответствие» для каждого предложения.

Я думаю, что вы сможете съесть всю оперативную память вашего компьютера после запуска этой программы всего за несколько минут на чем-то вроде одной главы книги. Это должно привести к остановке или аварийному завершению вашего процесса. Вы на самом деле пытались запустить это на большом наборе входов и посмотреть, что происходит? Если это так, то не имеет значения, выполняются ли вычисления параллельно.

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

0 голосов
/ 05 ноября 2011

Я не слишком горжусь этим (глядя на то, как я преобразовал defaultdict, чтобы избежать ошибок травления !!), но вот решение, которое работает:

...