如何使用R高效下载100万个图像并充分利用计算机/网络资源

时间:2017-03-22 03:51:36

标签: r performance image-processing download parallel-processing

我正在尝试下载包含大约100万个jpg文件的数据,其中我有各自的URL和所需的文件名。图像的平均文件大小约为120KB,范围从1KB到1MB。我想用R来下载图片。

我尝试了一些东西,并最终找到了一种让我在三小时内下载所有百万张图像的方法。我目前的策略是有效的,但这是一个有点荒谬的解决方案,我宁愿不再使用,我很困惑,为什么它甚至可以工作。我想了解发生了什么,并找到一种更优雅,更有效的方法来实现相同的结果。

我开始使用mapply和download.file(),但这只能控制每秒2个图像的速率。接下来,我将该过程与并行包并行化。这非常有效并且将速率提高到每秒9幅图像。我认为这是我能做到的最多,但我注意到我的笔记本电脑使用的资源远不及能力。我检查确保没有重要的磁盘或网络访问瓶颈,果然,它们的容量都没有超过10%。

所以我拆分了url信息并打开了一个新的R控制台窗口,在那里我在不同的数据段上运行相同脚本的第二个实例,以实现每秒18个图像。然后我继续打开越来越多的实例,为每个实例提供URL的完整列表的唯一部分。直到我打开12,才有任何减速的暗示。每个实例实际上每秒的下载量几乎呈线性增长,并且通过一些内存管理,我的最大下行速度达到了13 MB / s。

我附上了一张显示approximate total images being downloaded per second as a function of the number of instances running.

的图表

另附的是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。

提前谢谢。

1 个答案:

答案 0 :(得分:0)

cl <- makeCluster(detectCores())

这一行说明要创建一个后端群集,其中有许多节点等于你的核心。这可能是2,4或8,取决于你的机器有多强大。

正如您所注意到的那样,下载过程不受CPU限制,因此没有什么可以阻止您使群集尽可能大。用

之类的东西替换那一行
cl <- makeCluster(50)

并且您将同时下载50个R会话。增加数量,直到达到带宽或内存限制。