python - 使用 pycurl 进行 FTP 上传的进度函数调用过于频繁

标签 python upload ftp progress pycurl

我在 Ubuntu 12.0.4 上安装了 pycurl 7.19 版和 libcurl3 7.22 版(pycurl 和 libcurl 都是使用 apt-get 从 Ubuntu 存储库直接安装的)。我上传文件的代码是(“self”是我的包装对象):

self.curlTransfer = pycurl.Curl()
self.curlTransfer.setopt(pycurl.UPLOAD, 1)
self.curlTransfer.setopt(pycurl.USERPWD, '%s:%s'%(str(self.userName), str(self.password)))
self.curlTransfer.setopt(pycurl.NOPROGRESS, 0)
self.curlTransfer.setopt(pycurl.PROGRESSFUNCTION, self.__UpdateFileTransferProgress)
f = open(fileName, 'rb')
self.curlTransfer.setopt(pycurl.URL, 'ftp://' + self.ipAddress + self.path + destination)
self.curlTransfer.setopt(pycurl.INFILESIZE_LARGE, os.path.getsize(fileName))
self.curlTransfer.setopt(pycurl.READFUNCTION, f.read)
self.curlTransfer.perform()

我的回调函数“__UpdateFileTransferProgress”每秒被调用数千次,以至于传输速度比我关闭进度回调慢约 3 倍。我已经广泛搜索以解决此问题,我发现的唯一相关内容是 this curl bug report .听起来这个 bug 可能已经被修补了,但不清楚这个补丁是否已经进入我的版本(或者这是否是一个完全不同的问题)。

有没有人遇到过这个?我研究过手动更新到最新的 libcurl/pycurl 版本,但尝试解决依赖关系让我望而却步。与 ftplib 相比,我非常喜欢 pycurl 的性能(当禁用进度回调时),但我需要回调函数来跟踪传输进度。

最佳答案

查看更清洁解决方案的编辑!

我硬着头皮下载了 libcurl 和 pycurl 的最新源代码(实际上很容易构建/安装)。这改善了情况,因为进度函数现在每秒仅调用数百次而不是数千次,但在使用进度回调时仍然存在非常明显的性能影响。为了避免这种情况,我这样设置传输:

# Set transfer parameters.
self.curlTransfer.fp = open(fileName, 'rb')
self.curlTransfer.fileSize = os.path.getsize(fileName)
self.curlTransfer.setopt(pycurl.URL, 'ftp://' + self.ipAddress + self.path + destination)
self.curlTransfer.setopt(pycurl.INFILESIZE_LARGE, self.curlTransfer.fileSize)
self.curlTransfer.setopt(pycurl.READDATA, self.curlTransfer.fp)

# Store file.
self.curlTransfer.perform()

然后如果我想在另一个线程中获取进度:

def GetDataTransferred(self):
"""
Gets the amount of data transferred for the current file transfer.

@return Amount of data transferred (MB).
"""
try:

    # Try/except in case file is closed.
    try:
        return (float(self.curlTransfer.fp.tell())/float(myConstants.MB))
    except:
        if(self.curlTransfer.fileSize):
            return self.curlTransfer.fileSize

    return 0

except:
    Warning("Unable to get the amount of data transferred.")
    return 0

基本上我作弊并使用文件指针“告诉”来查看 pycurl 在传输中的位置。

编辑/解决:我最终通过修改/lib/progress.c 自己修复了 libcurl 中的错误,如我的 OP ( Imgur link ) 中的错误报告线程所示。听起来他们在他们的主干源代码中提交了修复,但它没有包含在他们的最新版本 (7.37.1) 中。我最终走这条路的原因是因为停止传输的最干净的方法是从进度函数返回非零值。您可以从 pycurl.READFUNCTION 返回非零值以停止传输,但是对于 FTP 上传,该函数每个 block 调用一次(~16KB)并且非常慢(改用 pycurl.READDATA 并提供文件指针)。现在我可以完全停止传输,使用他们预期的进度更新方法,并保持 libcurl 的高性能。

关于python - 使用 pycurl 进行 FTP 上传的进度函数调用过于频繁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24875538/

相关文章:

python - pip install MySQL-python,命令 "python setup.py egg_info"失败,错误代码为 1

python - 用于缩放 pandas 数据框中的列的 lambda 函数返回 : "' float' object has no attribute 'min' "

python - 将 python 元组放在函数签名中

python - 无法使用 python 访问 azure key Vault secret

jquery - ajax上传无法处理JSON响应或给出下载弹出窗口

websocket - Django channel 文件/图片上传

ruby-on-rails - 上传文件参数未通过 Controller

python - Python FTP 应用程序中的代理

java - FTPClient 如何解决 org.apache.commons.net.io.CopyStreamException : IOException caught while copying

java - Proftpd - 上传后的 0kb 文件