РЕШЕНО? Распараллеливание rsyn c (bash) посредством многопроцессорной обработки. Пул (Python): код работает как задумано, но rsyn c выдает странные ошибки - PullRequest
0 голосов
/ 09 июля 2020

[EDIT: я решил (?) Проблему самостоятельно и соответственно обновил вопрос]

У меня есть сценарий Python, который выполняет ежедневное резервное копирование большой папки (с подпапками). Поскольку папка стала слишком большой, а процесс резервного копирования занимает слишком много времени, из-за того, что процесс связан с ЦП, мне потребовалось изменить сценарий, чтобы использовать несколько ядер ЦП на сервере.

ПРИМЕЧАНИЕ. вероятно, это лучшие модули и функции для использования в этом варианте использования, но использование multiprocessing.Pool() применительно к subprocess.call к rsync является требованием, от которого я не мог отклониться.

  1. I пару недель боролся с этим, потому что у меня всегда было несколько дубликатов в папке назначения (отсюда исходный вопрос); Теперь я нашел неуклюжее, но работающее решение, разделив пути к файлам / папкам и снова объединив их (используя os.path.join): есть ли лучший способ сделать это?
  2. Хотя сценарий создает точную резервную копию исходной папке, я все еще получаю некоторые подозрительные сообщения об ошибках rsyn c во время выполнения, и я беспокоюсь, что все рухнет, как только будет выполнена неправильная комбинация процессов: может ли кто-нибудь взглянуть на них и сказать мне, если я нужно беспокоиться?

Вот (минимальная рабочая версия) кода, который я написал, прокомментировал:

#!/usr/bin/env python3

import os
import multiprocessing
import subprocess

#In this test /src/ and /dest/ are in the same folder of the script
source = os.path.join(os.getcwd(),"src")
destination = os.path.join(os.getcwd(),"dest")

def get_pathlist(folder):
    pathlist = []
    #No need for the FULL path of the dir/file
    #The source directory is in a global variable
    for root,dirs,files in os.walk(folder):
        for f in files:
            #Extract the sub-folder (if any)
            path = root[len(folder):]
            #Extract the filename
            item = f
            #Store the RELATIVE path in a tuple
            pathlist.append((path,item))
        for d in dirs:
            #Extract the sub-folder (if any)
            path = root[len(folder):]
            #Extract the folder name
            item = d
            #Store the RELATIVE path in a tuple
            pathlist.append((path,item))
    #Return the list of tuples
    return pathlist

def backup(path):
    #Source = root, path[0] = sub-folder, path[1] = file/dir name
    #NB: We input the FULL path of the source file/folder
    src = os.path.join(source,path[0],path[1])
    #Destination = root, path[0] = sub-folder
    #NB: We input the destination folder only (no need for the file/folder name)
    dest = os.path.join(destination,path[0])
    subprocess.call(['rsync', '-azq', src, dest])

if __name__ == "__main__":
    src_pathlist = get_pathlist(source)

    with multiprocessing.Pool(len(src_pathlist),maxtasksperchild=1) as mpool:
        mpool.map(backup,src_pathlist)

Как я уже упоминал, сценарий дает желаемый результат, но я получаю какие-то странные ошибки от rsyn c. Структура / src / выглядит следующим образом (для справки):

/src/
/1.txt
/Folder
/Folder/2.txt
/Folder/New_folder-A
/Folder/New_folder-B
/Folder/New_folder-C
/Folder/New_folder-A/3A.txt
/Folder/New_folder-B/3B.txt

Я получаю следующие ошибки:

rsync: change_dir "/Folder" failed: No such file or directory (2)
rsync: change_dir "/Folder" failed: No such file or directory (2)
rsync: change_dir "/Folder" failed: No such file or directory (2)
rsync: change_dir "/Folder" failed: No such file or directory (2)
rsync: change_dir "/Folder/New_folder-A" failed: No such file or directory (2)
rsync: change_dir#3 "/Folder" failed: No such file or directory (2)
rsync error: errors selecting input/output files, dirs (code 3) at main.c(720) [Receiver=3.1.3]
rsync: change_dir "/Folder/New_folder-B" failed: No such file or directory (2)
rsync: change_dir#3 "/Folder" failed: No such file or directory (2)
rsync error: errors selecting input/output files, dirs (code 3) at main.c(720) [Receiver=3.1.3]
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1207) [sender=3.1.3]
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1207) [sender=3.1.3]
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1207) [sender=3.1.3]
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1207) [sender=3.1.3]

Может ли кто-нибудь пролить свет на это? Любые предложения по улучшению ОЧЕНЬ приветствуются.

1 Ответ

0 голосов
/ 24 августа 2020
#!/usr/bin/env python3


import os
from multiprocessing import Pool
import subprocess

src = os.path.expanduser("~/Desktop/data/prod/")
dest = os.path.expanduser("~/Desktop/data/prod_backup/")

def get_pathlist(folder):
    pathlist = []
    
    for root, dirs, files in os.walk(folder):
        path = root[len(folder):]
        if dirs != []:
            for d in dirs:
                pathlist.append((path, d))
        for f in files:
            pathlist.append((path, f))

    return pathlist

def backup(path):
    source = os.path.join(src, path[0], path[1])
    destination = os.path.join(dest, path[0])
    subprocess.call(['rsync', '-arq', source, destination])

if __name__ == "__main__":
    src_pathlist = get_pathlist(src)

    with Pool(len(src_pathlist), maxtasksperchild=1) as pool:
        pool.map(backup, src_pathlist)
        

Мне удалось избавиться от некоторых ошибок, пройдя сначала по каталогам, а затем по файлам. Также есть некоторые изменения во внутренних циклах for для большей эффективности. И спасибо, ваш код мне помог, потому что я пытался сделать то же самое, но делал небольшие ошибки.

...