Как разделить один выходной tarfile между несколькими дочерними процессами? - PullRequest
0 голосов
/ 13 апреля 2019

Я работаю над сценарием резервного копирования, который использует модуль Python multiprocessing, чтобы разделить его работу между несколькими дочерними процессами.По большей части это относительно простой процесс.В условиях тестирования некоторое время назад я обнаружил, что могу получить увеличение скорости примерно на 20% по сравнению с однопроцессной обработкой, если я: 1. Разделю файлы, которые будут добавлены в выходной файл (ы), на отдельные задачи и;2. Пусть количество рабочих, равное количеству процессорных ядер машины (в моем случае, 4), делит эту работу между собой.

Я изначально реализовал это в Linux, используя объекты mp.Lock (), которыебыли брошены в словарь, аргументированный дочерним процессам во время выполнения.По понятным причинам это не работает в Windows (из-за ограничения метода создания процесса spawn ()), поэтому с тех пор я попытался:

  • Реализация процесса менеджера (кажется, неправильно делиться с детьми)
  • Включая объекты mp.Lock () в качестве аргументов задач, а не процессов (не может быть сделано, python принимает блокировки у детей только по наследству)
  • Отказаться от примитива блокировки в целом для реализации блокировки файлов на уровне FS / OS с использованием msvcrt и fcntl.

Когда я делаю это с помощью fcnt.lockf (), я могу правильно получить блокировки, но дочерний процесс не может затем записать свой вывод в файл, даже если он думает, что это происходит (как, например, исключение не вызывается).Моя реализация fcntl выглядит следующим образом:

import fcntl
                print("Gonna open %s" % self.tarf)
                #try:
                file = open(self.tarf, "a+b")
                file.seek(0)
                print("Can I lock?")
                fcntl.lockf(file, fcntl.LOCK_SH)
                print("got the lock")
                tar = tarfile.open(fileobj=file, mode="a:")
                print("tarfile opened")
                info = tar.gettarinfo(self.b, self.a)
                with open(self.b, "rb") as fd:
                    tar.addfile(info, fd)
                print("file inserted: %s" % self.a)
                tar.close()
                fcntl.lockf(file, fcntl.LOCK_UN)
                file.close()
                waiting = False

У меня два вопроса:

  • Есть ли правильный способ сделать это без использования mp.Lock ()объекты?
  • Есть ли особая хитрость в использовании менеджеров в окнах, на которую не распространяется аргумент прокси-объектов менеджера (скажем, dict_locks = manager.dict ()) дочернему процессу во время создания?

Я не очень хорош в этом переполнении стека, поэтому, если есть какая-либо дополнительная информация, которую я могу предоставить, пожалуйста, дайте мне знать.Я ожидал, что приведенный выше фрагмент кода заключается в том, что, получив блокировку fcntl в заданном дочернем процессе, передав заблокированный объект файла в tarfile.open, добавив файл с помощью tarfile.addfile (я также попробовал обычный старый tarfile.add с тем же результатом), и после этого закрытие / разблокировка файла будет работать.Я подозреваю, что что-то в блокировке файла молча препятствует операции tarfile.add, потому что файл, который запускает этот код, может определить, что файл успешно добавлен.Никаких исключений не возникает, но когда я вытаскиваю этот файл и проверяю его - нада.

...