使用Python下载时,应该选择多线程还是多进程?
最近我在做一个程序,可以从一个在线漫画网站下载漫画。这个程序能运行,但速度有点慢。所以我决定使用多线程或多进程来加快下载速度。以下是我的一些问题:
哪种方式更好?(这是一个Python 3的程序)
我觉得多进程肯定能行。如果我使用多进程,适合的进程数量是多少?这和我电脑的CPU核心数有关吗?
多线程可能也能行。这个下载工作显然需要很多时间来等待图片下载,所以我想当一个线程开始等待时,Python会让另一个线程继续工作。我这样理解对吗?
我读过大卫·M·比兹利的《Inside the New GIL》。如果我使用多线程,GIL会有什么影响?
3 个回答
其实对于这种任务,你并不一定需要多线程。你可以试试单线程的异步编程,像是使用Twisted这样的工具。
其实这没什么太大关系。确实,等待输入输出(IO)的线程不会影响其他线程的运行,而从网上下载东西就是一个依赖输入输出的任务,所以没必要把你的执行线程分散到多个CPU上。考虑到这一点,以及线程比进程更轻量,使用线程可能更好,但老实说,你不会感觉到太大的区别。
你应该使用多少线程,取决于你想要多频繁地访问那个网站。要注意礼貌,确保你的抓取行为不会被认为是拒绝服务攻击(DOS攻击)。
你可能会受到服务器上传速度的限制(如果你的网络连接比较快),或者下载速度的限制(如果你的网络连接比较慢)。
使用TCP连接时,启动连接会有一定的延迟。为了避免这种情况,HTTP服务器可以重复使用连接来请求多个资源。所以,你的客户端可以通过两种方式来减少这种延迟:
(a) 通过一个TCP连接下载多个资源,这样你的程序只在下载第一个文件时经历一次延迟。
(b) 每个TCP连接下载一个资源,使用多个连接,这样希望在任何时候至少有一个连接能够以全速下载。
如果选择(a),你需要了解如何使用你正在用的HTTP库来重复请求。好的HTTP库通常会有方法来重复使用连接。http://python-requests.org/ 是一个不错的Python HTTP库。
如果选择(b),你可能需要使用多线程或多进程的方法。我建议同时只用2到3个线程,因为如果线程太多,可能会导致带宽被分摊,增加被禁止多次下载的风险。
在这个情况下,GIL(全局解释器锁)并不重要,因为你的代码几乎不进行处理,大部分时间都在等待网络传输的数据。
如果想简单点,可以完全不使用Python,因为大多数类UNIX的环境都有很好的工具来实现这个功能。(如果你在Windows上,最好的选择是msys、cygwin,或者在VirtualBox上运行某种Linux版本,我个人喜欢Linux Mint。)如果你有一个文本文件,里面每行一个你想下载的URL,可以试试这个:
cat myfile.txt | xargs -n 1 --max-procs 3 --verbose wget
这个“xargs”命令配合这些参数,会从标准输入(在这个例子中是来自myfile.txt)读取以空格分隔的URL,并对每个URL运行“wget”。它会同时允许最多3个“wget”子进程运行,当其中一个完成(或出错)时,它会读取下一行并启动另一个子进程,直到所有输入的URL都处理完。如果你需要处理cookies或其他复杂的东西,curl可能比wget更合适。