Skip to main content
 首页 » 编程设计

python之是否有必要在多线程的 Paramiko 中为每个线程打开一个 SFTPClient

2024年09月07日34三少

我想使用多线程的 Paramiko 从远程服务器下载文件。

我想到了两个解决方案,但我不确定哪个是正确的(或更好的)。

解决方案 1: 假设 SFTPClient.get 是线程安全的(但我找不到任何提到的文档),一个简单的方法是:

from paramiko import SSHClient, AutoAddPolicy, SFTPClient 
from concurrent.futures import ThreadPoolExecutor 
from typing import List 
 
client = SSHClient() 
ciient.set_missing_host_key_policy(AutoAddPolicy()) 
client.connect( ... ) 
sftp = client.open_sftp() 
 
files_to_download: List[str] = ... 
 
with ThreadPoolExecutor(10) as pool: 
    pool.map(lambda fn: sftp.get(fn, fn), files_to_download) 

方案二:方案一

中有两个问题
  1. Paramiko 的 API 真的是线程安全的吗?
  2. 通过单个连接下载多个文件是否高效?

这是我的第二个解决方案:

from paramiko import SSHClient, AutoAddPolicy, SFTPClient 
from concurrent.futures import ThreadPoolExecutor 
from threading import Lock, local 
from typing import List 
 
client = SSHClient() 
ciient.set_missing_host_key_policy(AutoAddPolicy()) 
client.connect( ... ) 
thread_local = local() 
thread_lock  = Lock() 
 
files_to_download: List[str] = ... 
 
def download(fn: str) -> None: 
    """ 
    thread-safe and each thread has its own SFTPClient 
    """ 
    if not hasattr(thread_local, 'sftp'): 
        with thread_lock: 
            thread_local.sftp = client.open_sftp() 
    thread_local.sftp.get(fn, fn) 
 
with ThreadPoolExecutor(10) as pool: 
    pool.map(download, files_to_download) 

哪种解决方案更好?

请您参考如下方法:

Paramiko 不是线程安全的。

在一个连接上使用多个线程可能无法提供您希望的性能。您必须为每个线程打开一个单独的连接 (SSHClient/SFTPClient)。

只有一个连接,你会有更好的性能,只有在传输大量小文件的情况下。为此,请参阅 Slow upload of many small files with SFTP .