У меня есть рабочие и задачи:
workers = ['peter', 'paul', 'mary']
tasks = range(13)
Теперь я хочу разделить задачи на куски или пакеты работы, чтобы каждый рабочий мог работать над одним пакетом и выполнять примерно такой же объем работы, как и все остальные. В реальной жизни я хочу планировать пакетные задания для вычислительной фермы. Пакетные задания должны выполняться параллельно. Фактическое расписание и отправка выполняются с помощью коммерческого инструмента, такого как lsf или grid.
Некоторые примеры того, что я ожидаю:
>>> distribute_work(['peter', 'paul', 'mary'], range(3))
[('peter', [0]), ('paul', [1]), ('mary', [2])]
>>> distribute_work(['peter', 'paul', 'mary'], range(6))
[('peter', [0, 3]), ('paul', [1, 4]), ('mary', [2, 5])]
>>> distribute_work(['peter', 'paul', 'mary'], range(5))
[('peter', [0, 3]), ('paul', [1, 4]), ('mary', [2])]
Этот вопрос очень похож на вопросы здесь, здесь и здесь
Разница в том, что мне нужны эти функции в порядке или приоритете:
- Не использовать
len
, по возможности не создавать длинные структуры данных внутри - Принять генератор
- Возвратные генераторы
- Максимально возможное использование компонентов stdlib
Некоторые примечания о требованиях:
- Никаких диктовок специально: у меня есть рабочие с одним и тем же именем, которые могут выполнять несколько пакетов (имена хостов unix). Если ваше решение использует словари, это нормально, потому что мы всегда можем выполнять поиск рабочих операций с помощью пакетного перечисления.
- Произвольная длина: как рабочие процессы, так и задачи могут быть итерируемыми объектами любой длины >= 1. И они не должны разделяться поровну, как показано в примере выше, где Мэри получает только одну задачу.
- Порядок: Мне не важен. Я предполагаю, что другие могут предпочесть какой-то порядок, например [0,1], [2,3], [5], но мне все равно. Если ваше решение может сохранить или изменить порядок, возможно, на это стоит указать другим.
Я попытался обдумать itertools
и эту конкретную проблему и придумал следующий код, чтобы проиллюстрировать вопрос:
from itertools import *
def distribute_work(workers, tasks):
batches = range(len(workers))
return [ ( workers[k],
[t[1] for t in i]
) for (k,i) in groupby(sorted(zip(cycle(batches),
tasks),
key=lambda t: t[0]),
lambda t: t[0]) ]
Это удовлетворяет 4., но сортировка, скорее всего, нарушает 1.. и 2./3. даже не задумываются.
Вероятно, есть какое-то простое решение, объединяющее некоторые компоненты stdlib таким образом, о котором я не думал. А может и нет. Есть берущие?