我想从S3下载数千个文件。为了加快这个过程,我尝试了Python multiprocessing.Pool
,但我的表现非常不可靠。有时它可以工作,并且比单核版本快得多,但通常一些文件需要几秒钟,因此多处理运行所需的时间比单个进程要长。有几次我甚至得到ssl.SSLError: The read operation timed out
。
可能是什么原因?
from time import time
from boto.s3.connection import S3Connection
from boto.s3.key import Key
from multiprocessing import Pool
import pickle
access_key=xxx
secret_key=xxx
bucket_name=xxx
path_list = pickle.load(open('filelist.pickle','r'))
conn = S3Connection(access_key, secret_key)
bucket = conn.get_bucket(bucket_name)
pool = Pool(32)
def read_file_from_s3(path):
starttime = time()
k = Key(bucket)
k.key = path
content = k.get_contents_as_string()
print int((time()-starttime)*1000)
return content
results = pool.map(read_file_from_s3, path_list)
# or results = map(read_file_from_s3, path_list) for a single process comparison
pool.close()
pool.join()
[更新] 我最终只在我的多处理代码中添加超时重试(imap
+ .next(timeout)
),但这只是因为我不想改变太多在这一刻。如果你想做得对,请使用Jan-Philip的appraoch使用gevent。
答案 0 :(得分:1)
"原因可能是什么?"
细节不够。一个原因可能是您的私人Internet连接因太多并发连接而挨饿。但是既然你没有指定执行这段代码的环境,这就是纯粹的推测。
然而,没有任何猜测是你解决这个问题的方法是非常低效的。 multiprocessing
用于解决CPU限制问题。一次通过多个TCP连接检索数据不是CPU限制的问题。每个TCP连接产生一个进程是浪费资源。
这似乎很慢的原因是因为在你的情况下,一个进程花费大量时间等待系统调用返回(另一方面操作系统花了很多时间<强大>等待让网络模块按照它所做的去做(并且网络组件花费大量时间等待以使数据包通过网络到达)。)
您不需要多个进程来让您的计算机花费更少的时间等待。你甚至不需要多个线程。您可以使用协作调度从单个OS级别线程中的多个TCP连接中提取数据。在Python中,这通常使用greenlet完成。使用greenlet的更高级别模块是gevent。
网络上充满了基于gevent的示例,用于触发许多HTTP请求 - 并发。在适当的Internet连接的情况下,单个OS级别的线程可以同时处理数百或数千或数万个并发连接。在这些数量级上,问题随后演变为I / O绑定或 CPU绑定,具体取决于应用程序的确切用途。也就是说,网络连接或CPU内存总线或单个CPU内核限制了您的应用程序。
关于ssl.SSLError: The read operation timed out
- 类似错误:在网络世界中,您必须不时考虑这些事情,并决定(取决于您的应用程序的详细信息)您希望如何处理这些的情况。通常,简单的重试尝试是一个很好的解决方案。