Не получили ожидаемых результатов при использовании многопроцессорной обработки в Python - PullRequest
0 голосов
/ 24 марта 2020

После запуска приведенного ниже кода ожидаемый результат должен быть:

[50000000.0, 50000001.0, 50000002.0, ... 50000020.0], but now the result is weird
[50000000.0, 50000000.0, 50000000.0, 50000004.0, 50000004.0, 50000004.0, 50000008.0, 50000008.0, 50000008.0, 50000008.0, 50000008.0, 50000012.0, 50000012.0, 50000012.0, 50000016.0, 50000016.0, 50000016.0, 50000016.0, 50000016.0, 50000020.0]

Что-то не так с моим кодом? Python: 3.7.4, Операционная система: победа 10

from multiprocessing import Pool, Lock, Array, Queue
import os, time

array = Array('f', 20)
lock = Lock()


def long_time_task(i):
    print('Run task %s (%s)...' % (i, os.getpid()))
    start = time.time()

    total_count = 0
    for k in range(5*10**7): total_count += 1
    total_count += i
    lock.acquire()
    array[i] = total_count
    lock.release()

    end = time.time()
    print('Task %s runs %0.2f seconds.' % (i, (end - start)))


def init(l,a):
    global lock
    global array
    lock = l
    array = a


def mainFunc():
    print('Parent process %s.' % os.getpid())

    p = Pool(initializer=init, initargs=(lock,array))

    for i in range(20): p.apply_async(long_time_task, args=(i,))

    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')

if __name__ == '__main__':

    mainFunc()
    print(array[:])

Ответы [ 2 ]

1 голос
/ 24 марта 2020

После того, как перепробовал множество возможных методов исправления, чтобы найти его, в конце концов я обнаружил, что тип массива неправильный. вы должны использовать array = Array('i', 20), а не f
вывод:

All subprocesses done.
[50000000, 50000001, 50000002, 50000003, 50000004, 50000005, 50000006, 50000007, 50000008, 50000009, 50000010, 50000011, 50000012, 50000013, 50000014, 50000015, 50000016, 50000017, 50000018, 50000019]

1 голос
/ 24 марта 2020

Вы используете числа с плавающей запятой одинарной точности (32b):

array = Array('f', 20)

32b числа с плавающей запятой имеют только 23 + 1 бит, что соответствует биту выше 7 цифр (24 *) log10 (2) = 7.22).

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

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

Кроме этого:

  • массив неявно заблокирован, и вы никогда не читаете-обновляете-пишете каждая задача буквально просто устанавливает свою личную ячейку, явная блокировка бесполезна и избыточна
  • то, что вы делаете, является тривиальной картой, почему вы не используете Pool.map / Pool.imap, возможно, даже Poo.imap_unordered?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...