Python многопроцессорность против списков для нечетких - PullRequest
3 голосов
/ 14 января 2020

У меня есть два списка для сравнения друг с другом. Мне нужно сопоставить каждое str1 слово с каждым списком str2 слов. У меня есть список из 40 тысяч слов в str2. Я хочу попробовать multiprocessing, чтобы он работал быстрее.

Например:

str1 = ['how', 'are', 'you']
str2 = [['this', 'how', 'done'], ['they', 'were', 'here'], ['can', 'you', 'leave'], ['how', 'sad]]

Код, который я пробовал:

from multiprocessing import Process, Pool
from fuzzywuzzy import process 


def f(str2, str1):
    for u in str1:
        res = []
        for i in str2:
            Ratios = process.extract(u,i)
            res.append(str(Ratios))      
    print(res)
    return res

if __name__ == '__main__':
    str1 = ['how', 'are', 'you']
    str2 = [['this', 'how', 'done'], ['they', 'were', 'here'], ['can', 'you', 'leave'], ['how', 'sad]]
    for i in str2:
        p = Process(target=f, args=(i, str1))
        p.start()
        p.join()

Это не возвращает то, что я ожидал - я ожидал, что результат будет выглядеть как данные кадр:

words                   how are you
['this', 'how', 'done'] 100 0   0
['they', 'were', 'here'] 0  90  0
['can', 'you', 'leave']  0  80 100
['how', 'sad']           100 0   0

1 Ответ

2 голосов
/ 14 января 2020

Вы на самом деле не используете параллельную многопроцессорную обработку из-за этого l oop:

for i in str2:
    p = Process(target=f, args=(i, str1))
    p.start()
    p.join()

p.join() ожидает завершения каждого процесса последовательно. Таким образом, с этой конструкцией не будет никакого ускорения (обратите внимание, что может быть полезно просто создать новый чистый процесс для каждого случая, в некоторых ситуациях, когда вы, например, загружаете собственный код в DLL).

Вы должны храните объекты процессов и ожидайте их в отдельном l oop.

# create & store process objects
processes = [Process(target=f, args=(i, str1)) for i in str2]
# start processes
for p in processes:
   p.start()
# wait for processes to complete
for p in processes:
   p.join()

Обратите внимание, что у этого подхода есть несколько основных проблем:

  • , это может создать слишком много процессов работает в то же время
  • как просто получить возвращаемые значения из f?

При использовании вашего текущего метода возвращаемое значение теряется, если вы не сохраните его в manager объект. Метод map позволяет получить результаты, как показано в примере выше.

Вот почему существуют такие объекты, как пулы процессов. Небольшой пример использования:

from multiprocessing import Pool

def sq(x):
    return x**2

if __name__=="__main__":
    p = Pool(2)
    n = p.map(sq, range(10))
    print(n)

Здесь одновременно активны только 2 процесса.

Ваш код, адаптированный к пулам (непроверенный)

from multiprocessing import Pool
from fuzzywuzzy import process


def f(str2, str1):
    for u in str1:
        res = []
        for i in str2:
            Ratios = process.extract(u,i)
            res.append(str(Ratios))
    return res

if __name__ == '__main__':
    str1 = ['how', 'are', 'you']
    str2 = [['this', 'how', 'done'], ['they', 'were', 'here'], ['can', 'you', 'leave'], ['how', 'sad']]

    nb_processes = 4
    p = Pool(nb_processes)
    results = p.map(f, [(i,str1) for i in str2])

results - это список возвращаемых значений (список) от каждого вызова f, в порядке, указанном str2

...