使用带有线程的python下载文件

时间:2009-12-27 04:56:47

标签: python multithreading

我正在创建一个python脚本,它接受远程文件和n个线程的路径。文件的大小将除以线程数,当每个线程完成时,我希望它们将获取数据附加到本地文件。

如何管理它以便生成的线程按顺序附加到本地文件的顺序,以便字节不会被加扰?

另外,如果我要同时下载多个文件怎么办?

4 个答案:

答案 0 :(得分:9)

你可以用lock& c协调工作,但我建议改为使用Queue - 通常是在Python中协调多线程(和多处理)的最佳方法。

我会让主线程产生你认为合适的工作线程(你可能需要在性能之间进行校准,并通过试验在远程服务器上加载);每个工作线程在同一个全局Queue.Queue实例等待,例如,调用它workQ,因为“工作请求”(wr = workQ.get()将正确执行 - 每个工作请求都由一个单独获得工人线程,没有大惊小怪,没有muss)。

在这种情况下,“工作请求”可以只是一个三元组(具有三个项目的元组):远程文件的标识(URL或其他),请求从中获取数据的偏移量,字节数到得到它(请注意,这对于一个或多个文件提取也同样有效。)

主线程将所有工作请求推送到workQ(每个请求仅workQ.put((url, from, numbytes))),并等待结果转到另一个Queue实例,称之为resultQ (每个结果也将是一个三元组:文件的标识符,起始偏移量,字节字符串,即该偏移量下该文件的结果)。

当每个工作线程满足它正在执行的请求时,它会将结果放入resultQ并返回以获取另一个工作请求(或等待一个)。同时主线程(或者如果需要的话,单独的专用“写线程” - 即主线程还有其他工作要做,例如在GUI上)从resultQ获得结果并执行所需的{{1} },openseek操作将数据放在正确的位置。

有几种方法可以终止操作:例如,一个特殊的工作请求可能会要求接收它的线程终止 - 主线程放置write就像那些工作线程一样多在所有实际工作请求之后,然后在接收和写入所有数据时加入所有工作线程(存在许多替代方案,例如直接加入队列,使工作线程守护进程,因此当主线程终止时它们就会消失,等等。)

答案 1 :(得分:1)

您需要在每个线程上获取文件的完全独立部分。根据线程数计算块开始和结束位置。每个块显然必须没有重叠。

例如,如果目标文件长度为3000个字节,并且您想使用三个线程获取:

  • 线程1:获取字节1到1000
  • 线程2:获取字节1001到2000
  • 线程3:获取字节2001到3000

您将预先分配原始大小的空文件,并回写到文件中的相应位置。

答案 2 :(得分:0)

您可以使用线程安全的“信号量”,如下所示:

class Counter:
  counter = 0
  @classmethod
  def inc(cls):
    n = cls.counter = cls.counter + 1 # atomic increment and assignment
    return n

使用Counter.inc()在线程之间返回一个递增的数字,您可以使用它来跟踪当前的字节块。

话虽如此,没有必要将文件下载分成几个线程,因为下游比写入磁盘慢,所以一个线程总是在下一个下载之前完成。

最好和资源最少的方法就是让下载文件描述符直接链接到磁盘上的文件对象。

答案 3 :(得分:0)

“同时下载多个文件”,我推荐这篇文章:Practical threaded programming with Python。它通过将线程与队列结合起来提供了一个同时下载的相关示例,我认为值得一读。