【发布时间】:2015-10-24 04:45:20
【问题描述】:
我想使用 Python 将本地文件并行复制到多个远程主机。我正在尝试使用 asyncio 和 Paramiko 来做到这一点,因为我已经在我的程序中将这些库用于其他目的。
我使用BaseEventLoop.run_in_executor() 和默认ThreadPoolExecutor,它实际上是旧threading 库的新接口,以及Paramiko 的SFTP 功能来进行复制。
这是一个简单的例子。
import sys
import asyncio
import paramiko
import functools
def copy_file_node(
*,
user: str,
host: str,
identity_file: str,
local_path: str,
remote_path: str):
ssh_client = paramiko.client.SSHClient()
ssh_client.load_system_host_keys()
ssh_client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
ssh_client.connect(
username=user,
hostname=host,
key_filename=identity_file,
timeout=3)
with ssh_client:
with ssh_client.open_sftp() as sftp:
print("[{h}] Copying file...".format(h=host))
sftp.put(localpath=local_path, remotepath=remote_path)
print("[{h}] Copy complete.".format(h=host))
loop = asyncio.get_event_loop()
tasks = []
# NOTE: You'll have to update the values being passed in to
# `functools.partial(copy_file_node, ...)`
# to get this working on on your machine.
for host in ['10.0.0.1', '10.0.0.2']:
task = loop.run_in_executor(
None,
functools.partial(
copy_file_node,
user='user',
host=host,
identity_file='/path/to/identity_file',
local_path='/path/to/local/file',
remote_path='/path/to/remote/file'))
tasks.append(task)
try:
loop.run_until_complete(asyncio.gather(*tasks))
except Exception as e:
print("At least one node raised an error:", e, file=sys.stderr)
sys.exit(1)
loop.close()
我看到的问题是文件被串行复制到主机而不是并行。因此,如果单个主机复制需要 5 秒,两台主机需要 10 秒,以此类推。
我尝试了各种其他方法,包括放弃 SFTP 并将文件通过exec_command() 传送到每个远程主机上的dd,但副本总是连续发生。
我可能在这里误解了一些基本概念。是什么阻止了不同线程并行复制文件?
根据我的测试,似乎阻塞发生在远程写入时,而不是读取本地文件时。但为什么会这样,因为我们正在尝试针对独立远程主机的网络 I/O?
【问题讨论】:
-
可能
paramiko在内部使用了一些锁。你试过ProcessPoolExecutor吗? -
我用一些虚拟代码替换了
copy_file_node(),它运行良好,所以我认为是paramiko阻止了并发。如果是这种情况,ProcessPoolExecutor应该可以解决问题。您可以发布您的代码的ProcessPoolExecutor版本吗? -
@NickChammas 你确定网络带宽不是瓶颈吗?
-
@NickChammas 尝试同时通过 scp 手动将该文件复制到两台主机,看看需要多长时间。
-
@alexanderlukanin13 - 实际上,也许您对带宽的看法是正确的。如果尝试 2 个单独的
scp进程,一个总是在 ~23 秒内完成,而另一个需要 ~38 秒。哇。所以除了我对自己环境的假设之外,也许没有什么错...... :)
标签: python python-3.x sftp paramiko python-asyncio