我正在尝试下载包含大约100万个jpg文件的数据,其中我有各自的URL和所需的文件名。图像的平均文件大小约为120KB,范围从1KB到1MB。我想用R来下载图片。
我尝试了一些东西,并最终找到了一种让我在三小时内下载所有百万张图像的方法。我目前的策略是有效的,但这是一个有点荒谬的解决方案,我宁愿不再使用,我很困惑,为什么它甚至可以工作。我想了解发生了什么,并找到一种更优雅,更有效的方法来实现相同的结果。
我开始使用mapply和download.file(),但这只能控制每秒2个图像的速率。接下来,我将该过程与并行包并行化。这非常有效并且将速率提高到每秒9幅图像。我认为这是我能做到的最多,但我注意到我的笔记本电脑使用的资源远不及能力。我检查确保没有重要的磁盘或网络访问瓶颈,果然,它们的容量都没有超过10%。
所以我拆分了url信息并打开了一个新的R控制台窗口,在那里我在不同的数据段上运行相同脚本的第二个实例,以实现每秒18个图像。然后我继续打开越来越多的实例,为每个实例提供URL的完整列表的唯一部分。直到我打开12,才有任何减速的暗示。每个实例实际上每秒的下载量几乎呈线性增长,并且通过一些内存管理,我的最大下行速度达到了13 MB / s。
的图表另附的是10 simultaneous instances of R were running.
时资源监视器的屏幕截图我发现这个结果非常令人惊讶,我不太明白为什么这应该是可能的。是什么让每个单独的脚本运行得如此之慢?如果计算机可以运行此代码的12个实例而几乎没有收益递减,那么是什么阻止它运行速度快12倍?有没有办法在不打开全新R环境的情况下实现同样的目标?
以下是我特别询问的代码。不幸的是,我无法透露原始网址,但脚本几乎与我使用的相同。我用维基媒体的一些CC图像替换了我的数据。为了更好地进行复制,如果您有权访问此类内容,请将“图像”替换为您自己的大型URL列表。
library(parallel)
library(data.table)
images <-
data.table(
file = c(
"Otter.jpg",
"Ocean_Ferret.jpg",
"Aquatic_Cat.jpg",
"Amphibious_Snake_Dog.jpg"
),
url = c(
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Otter_and_Bamboo_Wall_%2822222758789%29.jpg/640px-Otter_and_Bamboo_Wall_%2822222758789%29.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Otter_Looking_Back_%2817939094316%29.jpg/640px-Otter_Looking_Back_%2817939094316%29.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/2/2a/Otter1_%2814995327039%29.jpg/563px-Otter1_%2814995327039%29.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/Otter_Profile_%2817962452452%29.jpg/640px-Otter_Profile_%2817962452452%29.jpg"
) #full URL's are redundant and unnecessary but I kept them in case there was some performance advantage over nesting a function inside download.file that combines strings.
)
#Download with Mapply (just for benchmarking, not actually used in the script)
system.time(
mapply(
function(x, y)
download.file(x, y, mode = 'wb', quiet = TRUE),
x = images$url,
y = images$file,
SIMPLIFY = "vector",
USE.NAMES = FALSE
)
)
#Parallel Download with clusterMap (this is what each instance is running. I give each instance a different portion of the images data table)
cl <- makeCluster(detectCores())
system.time(
clusterMap(
cl,
download.file,
url = images$url,
destfile = images$file,
quiet = TRUE,
mode = 'wb',
.scheduling = 'dynamic',
SIMPLIFY = 'vector',
USE.NAMES = FALSE
)
)
总之,我要问的问题是:
1)为什么我的解决方案表现如此?更具体地说,为什么1个脚本没有充分利用我的计算机资源?
2)使用R实现以下目标的更好方法是:在3小时内直接通过URL下载由100万jpeg图像组成的120GB。
提前谢谢。
答案 0 :(得分:0)
cl <- makeCluster(detectCores())
这一行说明要创建一个后端群集,其中有许多节点等于你的核心。这可能是2,4或8,取决于你的机器有多强大。
正如您所注意到的那样,下载过程不受CPU限制,因此没有什么可以阻止您使群集尽可能大。用
之类的东西替换那一行cl <- makeCluster(50)
并且您将同时下载50个R会话。增加数量,直到达到带宽或内存限制。