我的SFTP客户端存在性能问题。上传大文件(aprox。700MB)需要永远存在并退出失败(发生延迟超时)。上传25MB
文件的时间在一秒钟内完成。
这是实现ISFTPFile
:
def _create_target_from_source(target, source):
def _read_chunks_from_file(filename, chunk_size=1024 * 64):
with open(filename, 'rb') as fp:
chunk = fp.read(chunk_size)
while chunk:
yield chunk
chunk = fp.read(chunk_size)
offset = 0
for chunk in _read_chunks_from_file(source):
d = target.writeChunk(offset, chunk)
offset += len(chunk)
return d
并致电:
@defer.inlineCallbacks
def _upload(client):
mode_write = FXF_WRITE | FXF_CREAT | FXF_TRUNC
client_file = client.openFile(target, mode_write, {})
yield client_file.addCallback(_create_target_from_source, source)
defer.returnValue(client)
我在Consumer/Producer
找到了一些想法,但我不知道如何在我的示例中使用它们,或者它们是否与FileTransferClient
一起使用。有没有办法加快我的客户端上传?也许我的方法从一开始就错了?
第二个问题。有没有办法在推迟client.openFile
之前开始上传?
更新
说实话,我不确定我的代码是否很慢或我的方法是错误的,因为我将代码更改为:
def _create_target_from_source(target, source):
offsets_and_chunks = _read_chunks_with_offset_from_file(source)
d = _async_map(target.writeChunk, offsets_and_chunks)
return d
def _read_chunks_with_offset_from_file(filename, chunk_size):
with open(filename, 'rb') as fp:
chunk = fp.read(chunk_size)
offset = 0
while chunk:
yield offset, chunk
chunk = fp.read(chunk_size)
offset += chunk_size
def _async_map(writeChunk, payload):
try:
offset, chunk = next(payload)
except StopIteration:
return defer.succeed(True)
d = writeChunk(offset, chunk) # this is sloooooooooooow
d.addCallback(lambda _: _async_map(writeChunk, payload))
return d
无法解决我的性能问题。例如,当我测试paramiko.SFTPClient
上传700MB文件需要33秒时。
我认为我在SFTP上传文件时做错了,但我不知道到底是什么。
答案 0 :(得分:0)
这段代码很慢(并且容易出错)的原因是它将整个文件读入内存并将所有块排队等待写入远程文件。
以下是发生这种情况的地方:
for chunk in _read_chunks_from_file(source):
d = target.writeChunk(offset, chunk)
offset += len(chunk)
循环一直运行 - 同步。您可以做的一个改变是等待每个writeChunk
成功,然后再继续下一个。
有许多方法可以将同步循环转换为异步循环。您可以在每次迭代时使用inlineCallbacks
并生成d
。或者您可以使用How refactor readChunk from SFTPFile to stop using inlineCallbacks?的答案在没有inlineCallbacks
的情况下执行类似的操作。