首页 新闻 会员 周边 捐助

多线程下载同一个资源,如果保证同时只有一个线程进行存储资源?

0
悬赏园豆:50 [已解决问题] 解决于 2017-02-27 14:48

现在有个需求:

  用户输入图片URL,首先本地检测图片是否存在,如果存在,则直接输出,如果不存在则下载然后保存。

问:当多个线程执行这步的时候,如果保证只有一个线程在下载?并且其他线程可以在存储线程执行完成后执行输出操作?

 

锁的话是用不了的,因为一锁的话,几乎所有的请求都在等待了。

 

我现在的做法是使用一个HashSet来存储,每次下载的时候先检测HashSet中是否存在,如果存在,就等待10秒,然后重新走一遍。

大壮他哥的主页 大壮他哥 | 初学一级 | 园豆:11
提问于:2017-02-13 19:17
< >
分享
最佳答案
0

不太明白你的实现,如果单独考虑单进程的玩意,你那HashSet不就可以做锁了么?(最好换成字典,key为url或者图片唯一标识,value为超时时间)

按照字典实现ConcurrentDictionary<string,DateTime>,每次在执行到这里时首先判断字典中是否存在对应key,如果有则检查其value是否过期,如果过期则更新为当前时间+过期时间,同时更改上下文标识表示我可以开始下载及保存逻辑;反之则更改代码上下文标识已表示其他线程已经在操作,然后重复上述逻辑(前几句描述为过程,实现核心为ConcurrentDictionary#AddOrUpdate方法)。

如果考虑多进程场景则考虑将这个锁移到第三方组件中,如zookeeper或redis中(建议redis,因为其执行过程单线程确保数据线程安全性,但由于整个逻辑牵扯步骤过多,需要使用lua脚本加载到redis中单线程执行)

收获园豆:40
Daniel Cai | 专家六级 |园豆:10424 | 2017-02-16 10:17

你好,我现在的做法 是把 URL当作了一个key存储到了ConcurrentDictionary里面,已经可以实现了这个业务需求了,后期如果涉及到分布式的话,我会把ConcurrentDictionary换成redis来做.

大壮他哥 | 园豆:11 (初学一级) | 2017-02-16 10:21

@大壮他哥: 

1.确保你的value中包含超时信息,因为这里可能无法预料获取“锁”的线程会出现什么情况,同时也为了保证其他线程不至于等待时间过久影响体验

2.ConcurrentDictionary几个原子性方法要小心点,确保其后面的委托方法为惰性(之前我就掉过这个坑)

Daniel Cai | 园豆:10424 (专家六级) | 2017-02-16 10:27
其他回答(1)
0

下载下来往一个内存缓存里放.

再起一个独立线程.从缓存里拿数据往磁盘写

收获园豆:10
吴瑞祥 | 园豆:29449 (高人七级) | 2017-02-13 21:05

谢谢您的回复,这种方案我先尝试一下。

支持(0) 反对(0) 大壮他哥 | 园豆:11 (初学一级) | 2017-02-14 09:18
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册