同步远程文件下载

本文关键字:文件下载 同步 | 更新日期: 2023-09-27 18:12:43

前言:这是一个自我分配的纯合成任务,学习(并记住我已经知道的)c#线程、同步和数据结构。

的故事:

假设我有一个字典<string, string>,它表示通过某个键到文件的路径(http),即:

foo => http://domain.tld/file1
bar => http://domain2.tld/file2

我想实现一个类,它将实现一个有两个方法的接口:

String Rand();
String Get(String key);

第一个方法将从所有可用的文件中随机选择文件,并且Get将返回一个特定的文件,或者更准确地说是一个下载文件的本地路径。

类应该是线程安全的,所以如果几个线程请求相同的keyGet()Rand()选择相同的项目-然后只有一个线程应该实际下载一个文件到本地驱动器,或者路径应该立即检索,如果一个文件已经下载。

所以,这就是我被困的地方。

我如何同步"下载器",使相同的文件不会被下载两次?

如何限制同时下载的数量?

PS:我不是问任何代码,只是一个关键字的数据结构,类和模式,将有助于这项任务。

PPS:这个任务是100%抽象的,所以如果你认为一些需求的变化可以使它对我(作为一个学习者)更有趣/有用-欢迎你的变化。

同步远程文件下载

因此,满足要求并使用await/async的"downloader"类的"最终"版本是:

class Downloader
{
    private IDictionary<string, string> _map;
    private IDictionary<string, string> _storage = new ConcurrentDictionary<string, string>();
    private ConcurrentDictionary<string, Task<string>> _progress = new ConcurrentDictionary<string,Task<string>>();
    public Downloader(IDictionary<string, string> map)
    {
        _map = map ?? new Dictionary<string, string>();
    }
    public async Task<string> Get(string key)
    {
        string path;
        if (!_map.TryGetValue(key, out path))
        {
            throw new ArgumentException("The specified key wasn't found");
        }
        if (_storage.ContainsKey(key))
        {
            return _storage[key];
        }
        Task<string> task;
        if (_progress.TryGetValue(key, out task))
        {
            return await task;
        }
        task = _retrieveFile(path);
        if (!_progress.TryAdd(key, task))
        {
            return await Get(key);
        }
        _storage[key] = await task;
        return _storage[key];
    }
    private async Task<string> _retrieveFile(string path)
    {
        Console.WriteLine("Started retrieving {0}", path);
        await Task.Delay(3000);
        Console.WriteLine("Finished retrieving {0}", path);
        return path + " local path";
    }
}

整个代码和示例输出:http://pastebin.com/LdFvPDbQ