【发布时间】:2011-05-22 12:48:03
【问题描述】:
好的,我有点不确定如何最好地命名这个问题 :) 但是假设这种情况,你是 出去并获取一些网页(带有各种网址)并将其缓存在本地。即使使用多个线程,缓存部分也很容易解决。
但是,假设一个线程开始获取一个 url,几毫秒后另一个线程想要获取相同的 url。有没有什么好的模式可以让秒线程的方法在第一个线程上等待以获取页面,将其插入缓存并返回它,这样您就不必执行多个请求。即使对于大约需要 300-700 毫秒的请求,开销也足够少?并且没有锁定对其他 url 的请求
基本上,当对相同 url 的请求彼此紧接时,我希望第二个请求“搭载”第一个请求
当您开始获取页面并锁定它时,我有一些松散的想法,即有一个字典,您可以在其中插入一个带有键作为 url 的对象。如果有任何匹配的键已经是对象,则锁定它,然后尝试获取实际缓存的 url。
我有点不确定细节,但是为了使其真正线程安全,使用 ConcurrentDictionary 可能是其中的一部分...
这样的场景有什么通用的模式和解决方案吗?
分解错误行为:
线程 1:检查缓存,它不存在所以开始获取 url
线程 2:开始获取相同的 url,因为它仍然不存在于缓存中
线程1:完成并插入缓存,返回页面
线程 2:完成并插入缓存(或丢弃),返回页面
分解正确行为:
线程 1:检查缓存,它不存在所以开始获取 url
线程 2:想要相同的 url,但看到它当前正在被获取,所以等待线程 1
线程1:完成并插入缓存,返回页面
线程 2:通知线程 1 已完成并返回它获取的页面线程 1
编辑
到目前为止,大多数解决方案似乎都误解了这个问题,只解决了缓存问题,正如我所说的那样,这不是问题,问题是在进行外部 Web 抓取以进行第二次抓取时在第一次抓取之前完成缓存它以使用第一个结果而不是第二个
【问题讨论】:
-
我的回答确实解决了您在编辑中提出的问题。
-
@Luke,您当前的解决方案似乎确实是我正在寻找的,谢谢!我会等几个小时等待任何替代解决方案,然后我会关闭问题
-
您是否考虑过一种解决方案,您可以使用某种同步字典(例如 ConcurrentDictionary),其中 url 作为键,IAsyncResult 作为值?如果线程 2 将尝试获取当前正在由线程 1 下载的页面,则它只需要等待 IAsyncResult 直到它完成然后获取页面内容(IAsyncResult 可能不是正确的选择,但你会得到想法...)。
标签: c# multithreading design-patterns concurrency c#-4.0