Есть ли простой Python 3 способ сделать параллель для l oop, как в Java? - PullRequest
1 голос
/ 20 июня 2020

Я приехал из Java. В Java 8 и выше у нас есть API параллелизма (служба исполнителя, защелка обратного отсчета, Cycli c барьер, API параллельного потока). Есть ли такой простой API в Python 3? Я нашел только много уродливого кода, в котором все изобретают колесо, например, операцию соединения вилки на жестко запрограммированных спецификациях c dict или списке с настраиваемым кодом.

Допустим, у меня есть dict с 50000 элементами и он содержит целое число group_id. Я хочу подсчитать, сколько элементов в каждой группе.

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

import collections

dataset_dict = collections.defaultdict(int)

for img, group_id in dataset:
    dataset_dict[classes[group_id]] += 1

print(dataset_dict)

Лучшее, что я нашел, это Библиотека Ray в Python 3, но API очень низкого уровня и не соответствует уровню других современных языков. С бумом лямбд и машинного обучения PyTorch / Keras в Python, прогрессом в Typescript и капитальным ремонтом с Java 8, мне действительно нужно что-то подобное в Python 3.

Можете ли вы предоставить несколько простых пример для кода выше? Я пробовал кое-что с Рэем, и это кажется самым простым. Но проблема заключается в записи приращений в общую переменную. Возможно, вам известен более современный API для Python 3.

Ожидаемое поведение состоит в том, что 50 000 элементов будут разделены по количеству процессоров. Каждый поток суммирует количество групп, а затем объединяет результаты в окончательный результат. Я думаю, что в этом случае это может быть просто пул Fork Join. Мне нужен идеальный чистый код, легко читаемый. Итак, вы просто читаете код и получаете тот момент «ага», как будто он простой, но при этом умный, потому что красота в простоте.

1 Ответ

1 голос
/ 20 июня 2020

Одно фундаментальное различие между Python и Java состоит в том, что Python имеет глобальную блокировку интерпретатора . Это немного усложняет реализацию низкоуровневой многопоточности так же, как, например, для Java.

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

Ray - это полностью распределенная система, поэтому она может помочь распараллелить / распределить код python по ядер на одной машине или во всем кластере. С Ray вы можете использовать Parallel Iterator вместо списка и обернуть свой dataset_dict в субъект . Это может выглядеть примерно так:

dataset_iter = from_items(dataset)
dataset_iter.for_each(lambda x: ray.get(dataset_dict.increment.remote(x)))
# This line starts the processing
list(dataset_iter.gather_async())

и dataset_dict будет выглядеть примерно так:

import collections
@ray.remote
class Counter:
 def __init__(self):
  self.counter = collections.Counter()

 def increment(self, key):
  self.counter[key] += 1

dataset_dict = Counter.remote()
...