使用ftplib进行多线程上传

3

我正在尝试进行多线程上传,但是遇到了错误。

我猜想可能无法使用ftplib实现多线程?

以下是我的代码:

    class myThread (threading.Thread):
    def __init__(self, threadID, src, counter, image_name):
        self.threadID = threadID
        self.src = src
        self.counter = counter
        self.image_name = image_name
        threading.Thread.__init__(self)
    def run(self):
        uploadFile(self.src, self.image_name)

def uploadFile(src, image_name):
    f = open(src, "rb")            
    ftp.storbinary('STOR ' + image_name, f)
    f.close()

ftp = FTP('host')   # connect to host, default port
ftp.login()               # user anonymous, passwd anonymous@   
dirname = "/home/folder/"
i = 1   
threads = []

for image in os.listdir(dirname):
    if os.path.isfile(dirname + image):
        thread = myThread(i , dirname + image, i, image )   
        thread.start()
        threads.append( thread )        
        i += 1  

for t in threads:
    t.join()

我遇到了很多ftplib错误,例如

raise error_reply, resp error_reply: 200 Type set to I

如果我一个一个上传,一切都正常工作。


即使 ftplib 具有多线程支持,这个程序的工作方式会是什么样的?因为每个线程都试图上传完全相同的文件。 - matt b
为什么结果一样?如果我不使用线程,在同一个“for”循环中调用函数,它可以正确地处理文件夹中的所有文件。 - Arty
糟糕,我误读了文件打开的代码。无论如何,我认为可以肯定地假设该库不提供线程安全或并发的FTP会话。 - matt b
无论如何,ftplib没有多线程支持,对吧? - Arty
太糟糕了。即使有良好的连接,上传大量文件也需要很长时间。 - Arty
2个回答

5
你尝试将连接代码放在线程内部了吗?
换句话说,让每个线程使用自己单独的连接进行FTP.host()和FTP.login()。服务器可能不喜欢在单个连接上同时进行多个上传,因为它可能一次只解析一个命令,无法处理第二个上传或“STOR”命令。但是,如果您可以从同一IP地址进行多个连接,则会有单独的会话,可以在其中发出“STOR”命令。
以下是示例:
    class myThread (threading.Thread):
        def __init__(self, threadID, src, counter, image_name):
             ###############
             #Add ftp connection here!
             self.ftp = FTP('host')   # connect to host, default port
             self.ftp.login()               # user anonymous, passwd anonymous@   
             ################
             self.threadID = threadID
             self.src = src
             self.counter = counter
             self.image_name = image_name
             threading.Thread.__init__(self)
        def run(self):
             uploadFile(self.src, self.image_name)

    def uploadFile(src, image_name):
          f = open(src, "rb")            
          self.ftp.storbinary('STOR ' + image_name, f)
          f.close()

     dirname = "/home/folder/"
     i = 1   
     threads = []

     for image in os.listdir(dirname):
          if os.path.isfile(dirname + image):
             thread = myThread(i , dirname + image, i, image )   
             thread.start()
             threads.append( thread )        
             i += 1  

      for t in threads:
          t.join()

看看它是否表现更好。

附言:不确定是否所有选项卡都对齐。


1
谢谢,这个方法可行,虽然使用多线程上传会慢一些。所以我可能要找另一个库或者忍受单线程上传。 - Arty
对于为什么这个速度较慢,你有什么见解吗? - Matt
1
@Matt,这是因为与FTP服务器建立了多个连接,所以速度较慢。 - glennmark

1

我最终使用了信号量来限制FTP连接的使用,每次只允许一个线程使用。与为每个线程创建连接相比,共享连接更快。在您的情况下,代码如下:

from threading import Semaphore

ftp_semaphore = Semaphore(1)  # limiting connection to only one thread

class myThread (threading.Thread):
    def __init__(self, threadID, src, counter, image_name):
        self.threadID = threadID
        self.src = src
        self.counter = counter
        self.image_name = image_name
        threading.Thread.__init__(self)
    def run(self):
        uploadFile(self.src, self.image_name)

def uploadFile(src, image_name):
    f = open(src, "rb")
    with ftp_semaphore:     
        ftp.storbinary('STOR ' + image_name, f)
        f.close()

ftp = FTP('host')   # connect to host, default port
ftp.login()               # user anonymous, passwd anonymous@   
dirname = "/home/folder/"


i = 1   
threads = []

for image in os.listdir(dirname):
    if os.path.isfile(dirname + image):
        thread = myThread(i , dirname + image, i, image )   
        thread.start()
        threads.append( thread )        
        i += 1  

for t in threads:
    t.join()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接