SDWebImage在多线程下载图片时防止错乱的策略

在我们使用sd的时候,对tableView  上cell得图片进行异步下载的时候会遇到这样一个问题:

由于cell的重用机制,在我们加载出一个cell的时候imageView数据源开启一个下载任务并返回一个image,当cell重用时,其数据源又会开启一个下载任务下载新的image,但关联的对象是同一个imageView,这个时候直接setImage时会发生错乱。

SDWebImage的处理是:

imageView对象会关联一个下载列表(列表是给AnimationImages用的,这个时候会下载多张图片),当tableview滑动,imageView重设数据源(url)时,会cancel掉下载列表中所有的任务,然后开启一个新的下载任务。这样子就保证了只有当前可见的cell对象的imageView对象关联的下载任务能够回调,不会发生image错乱。

同时,SDWebImage管理了一个全局下载队列(在DownloadManager中),并发量设置为6.也就是说如果可见cell的数目是大于6的,就会有部分下载队列处于等待状态。而且,在添加下载任务到全局的下载队列中去的时候,SDWebImage默认是采取LIFO(last in,first out)策略的,具体是在添加下载任务的时候,将上次添加的下载任务添加依赖为新添加的下载任务。(在SDWebImageDownloader的callback中有这样一段代码):

  [wself.downloadQueueaddOperation:operation];

        if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {

            // Emulate LIFO execution order by systematically adding new operations as last operation's dependency

            [wself.lastAddedOperationaddDependency:operation];

            wself.lastAddedOperation = operation;

        }

 

另外一种解决方案是:

imageView对象和图片的url相关联,在滑动时,不取消旧的下载任务,而是在下载任务完成回调时,进行url匹配,只有匹配成功的image会刷新imageView对象,而其他的image则只做缓存操作,而不刷新UI。

同时,仍然管理一个执行队列,为了避免占用太多的资源,通常会对执行队列设置一个最大的并发量。此外,为了保证LIFO的下载策略,可以自己维持一个等待队列,每次下载任务开始的时候,将后进入的下载任务插入到等待队列的前面。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当涉及到在 Python 中使用多线程下载图片,您可以使用 `threading` 模块和 `requests` 库来实现。下面是一个简单的示例代码: ```python import threading import requests def download_image(url, filename): response = requests.get(url) with open(filename, "wb") as file: file.write(response.content) print(f"下载完成: {filename}") # 图片链接列表 image_urls = [ "https://example.com/image1.jpg", "https://example.com/image2.jpg", "https://example.com/image3.jpg" ] # 创建线程列表 threads = [] for index, url in enumerate(image_urls): # 设置文件名 filename = f"image{index + 1}.jpg" # 创建并启动线程 thread = threading.Thread(target=download_image, args=(url, filename)) thread.start() threads.append(thread) # 等待所有线程完成 for thread in threads: thread.join() print("所有图片下载完成") ``` 在上述示例代码中,我们定义了一个 `download_image` 函数,它接受图片的 URL 和要保存的文件名作为参数,并使用 `requests` 库下载图片并保存到本地文件中。然后,我们创建了一个包含图片链接的列表 `image_urls`。 接下来,我们使用 `threading.Thread` 创建了多个线程,并将 `download_image` 函数作为目标函数传递给每个线程。我们还为每个线程设置了不同的文件名。然后,我们依次启动每个线程,并将它们添加到线程列表 `threads` 中。 最后,我们使用 `thread.join()` 等待所有线程完成下载任务,并在所有线程完成后输出提示信息。 这样,您就可以使用多线程来同下载多个图片。请注意,该示例只是一个简单的示例,实际应用中可能需要处理更多的异常情况和优化控制并发数量等问题。 希望这对您有所帮助!如果您有任何其他问题,请随提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值