使用 Multiprocessing 和 PySftp 并行下载

Parallel downloads with Multiprocessing and PySftp

我正在尝试创建代码以使用 pysftp 和多处理库以相同类型下载 N 个文件。我进行了基本的 python 培训,得到了一些代码并将它们组合成一个,但我无法解决它。如果有人帮助我,我将不胜感激。错误发生在 vFtp.close() 命令之后。在假设开始同时下载的部分。

from multiprocessing import Pool
import pysftp
import os

vHost='10.11.12.13'
vLogin='admin'
vPwd='pass1234'
vFtpPath='/export/home/'

os.chdir('d:/test/')
os.getcwd()

cnopts=pysftp.CnOpts()
cnopts.hostkeys = None

vFtp=pysftp.Connection(vHost,username=vLogin,password=vPwd,cnopts=cnopts)
vFtp.cwd(vFtpPath)
vObjectList=vFtp.listdir()
vFileList=[]
vFoldList=[]

for vObject in vObjectList:
    vType=str(vFtp.lstat(vObject))[:1]
    if vType!='d': 
        vFileList.append(vObject)
    else:   
        vFoldList.append(vObject)

vFtp.close()

def fDownload(vFileAux):
    vFtpAux=pysftp.Connection(vHost,username=vLogin,password=vPwd,cnopts=cnopts)
    vFtpAux.cwd(vFtpPath)
    vFtpAux.get(vFileAux,preserve_mtime=True)
    vFtpAux.close()

if __name__ == "__main__":
    vPool=Pool(3)
    vPool.map(fDownload,vFileList)  

您似乎在尝试获取文件列表,然后使用多个进程同时下载它们。

不要手动检查文件,而是尝试在连接对象上使用 walktree 方法:pysftp walktree

这是我在 Python 3.5 中制作的一个工作示例。我只是使用本地 ftp 服务器和小文件,所以我模拟了下载延迟。更改 max_workers 参数以设置同时下载的数量。

"""Demo using sftp to download files simultaneously."""
import pysftp
import os
from concurrent.futures import ProcessPoolExecutor
import time


def do_nothing(s):
    """
    Using this as the callback for directories and unknown items found
    using walktree.
    """
    pass


def download(file):
    """
    Simulates a 1-second download.
    """
    with pysftp.Connection(
            host='convox', username='abc', private_key='/home/abc/test') as sftp:

        time.sleep(1)
        print('Downloading {}'.format(file))
        sftp.get(file)


def get_list_of_files(remote_dir):
    """
    Walks remote directory tree and returns list of files.
    """
    with pysftp.Connection(
            host='convox', username='abc', private_key='/home/abc/test') as sftp:

        files = []

        # if this finds a file it will send the filename to the file callback
        # which in this case just appends to the 'files' list
        sftp.walktree(remote_dir, fcallback=files.append,
                      dcallback=do_nothing, ucallback=do_nothing)

    return files

if __name__ == '__main__':
    remote_dir = '/home/abc/remoteftp/'
    download_target = '/home/abc/localftp/'

    # if you don't specify a localpath in sftp.get then it just downloads to
    # the os cwd, so set it here
    os.chdir(download_target)

    files = get_list_of_files(remote_dir)
    pool = ProcessPoolExecutor(max_workers=4)
    pool.map(download, files)

编辑:ProcessPoolExecutor 适用于 运行 多个 cpu 核心上的东西,并且会受到处理器的限制。对于下载等网络任务,您可以改用线程。在上面的代码中,这只是一个变化:导入并使用 ThreadPoolExecutor 而不是 ProcessPoolExecutor。那你可以多用max_workers.