Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
可移植.NET框架中并发集合的类似物_.net_Silverlight_Collections_Concurrency_Portable Class Library - Fatal编程技术网

可移植.NET框架中并发集合的类似物

可移植.NET框架中并发集合的类似物,.net,silverlight,collections,concurrency,portable-class-library,.net,Silverlight,Collections,Concurrency,Portable Class Library,将代码移动到可移植框架中,我发现在可移植类库(PCL)中根本没有可用的并发集合,这很好地解释了这一点 但我仍然需要并发字典模拟才能在那里运行。 与修改性能相比,我对读取/包含性能更感兴趣。字典集合的最大好处是快速键访问和快速包含评估。 所有字典都使用不同的复杂算法(请检查此项),从头开始编写自己的字典将非常困难 所以,我尝试重用源代码的原始ConcurrentDictionary从(您可以为每个基类)。 但是,它非常复杂,并且使用几十个私有类和低级函数来管理内存。这不是偶然的,它从一开始就在PC

将代码移动到可移植框架中,我发现在可移植类库(PCL)中根本没有可用的并发集合,这很好地解释了这一点

但我仍然需要并发字典模拟才能在那里运行。
与修改性能相比,我对读取/包含性能更感兴趣。

字典集合的最大好处是快速键访问和快速包含评估。 所有字典都使用不同的复杂算法(请检查此项),从头开始编写自己的字典将非常困难

所以,我尝试重用源代码的原始ConcurrentDictionary从(您可以为每个基类)。 但是,它非常复杂,并且使用几十个私有类和低级函数来管理内存。这不是偶然的,它从一开始就在PCL中不可用:)

第二个想法是制作普通字典的包装器,并在每个方法调用中添加锁部分。尽管关键部分并不昂贵,但它导致了性能的急剧下降

因此,我以Dictionary包装器的清晰互锁实现作为结束。通常情况下,普通字典支持从不同线程读取和枚举,只要不同时修改。 所以,每一次改变,我们都会克隆所有的字典。所有在这段时间内读取它的线程都将继续迭代较旧的副本

public class InterlockedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
    private Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();


    public TValue this[TKey key]
    {
        get
        {
            return _dictionary[key];
        }
        set
        {                
            ApplyAndChange(dict => dict[key] = value);
        }
    }

    public Dictionary<TKey, TValue>.KeyCollection Keys
    {
        get
        {
            return _dictionary.Keys;
        }
    }

    public Dictionary<TKey, TValue>.ValueCollection Values
    {
        get
        {
            return _dictionary.Values;
        }
    }

    public int Count
    {
        get
        {
            return _dictionary.Count;
        }
    }


    public void Add(KeyValuePair<TKey, TValue> item)
    {
        ApplyAndChange(dict => dict.Add(item.Key, item.Value));
    }

    public void Clear()
    {
        _dictionary = new Dictionary<TKey, TValue>();
    }

    public bool ContainsKey(TKey key)
    {
        return _dictionary.ContainsKey(key);
    }

    public void Add(TKey key, TValue value)
    {
        ApplyAndChange(dict => dict.Add(key, value));
    }

    public bool Remove(TKey key)
    {
        bool result = false;
        ApplyAndChange(dict => result = dict.Remove(key));
        return result;
    }


    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }


    private void ApplyAndChange(Action<Dictionary<TKey, TValue>> action)
    {
        Dictionary<TKey, TValue> initialDictionary, updatedDictionary, replacedDictionary;
        do
        {
            initialDictionary = _dictionary;
            updatedDictionary = new Dictionary<TKey, TValue>(initialDictionary);
            action(updatedDictionary);
        } while (Interlocked.CompareExchange(ref _dictionary, updatedDictionary, initialDictionary) != initialDictionary);
    }
}
公共类InterlocatedDictionary:IEnumerable
{
专用词典_Dictionary=新词典();
公共TValue此[TKey]
{
得到
{
返回字典[键];
}
设置
{                
ApplyAndChange(dict=>dict[key]=value);
}
}
public Dictionary.KeyCollection密钥
{
得到
{
返回_dictionary.Keys;
}
}
public Dictionary.ValueCollection值
{
得到
{
返回_dictionary.Values;
}
}
公共整数计数
{
得到
{
返回_dictionary.Count;
}
}
公共作废添加(KeyValuePair项)
{
ApplyAndChange(dict=>dict.Add(item.Key,item.Value));
}
公共空间清除()
{
_字典=新字典();
}
公共bool ContainsKey(TKey)
{
返回_dictionary.ContainsKey(key);
}
公共无效添加(TKey键,TValue值)
{
ApplyAndChange(dict=>dict.Add(key,value));
}
公用门移除(TKey)
{
布尔结果=假;
ApplyAndChange(dict=>result=dict.Remove(key));
返回结果;
}
公共IEnumerator GetEnumerator()
{
返回_dictionary.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
返回GetEnumerator();
}
私有无效应用程序更改(操作)
{
字典初始字典、更新字典、替换字典;
做
{
initialDictionary=\u字典;
updatedDictionary=新字典(初始字典);
行动(更新的对话);
}while(interlocated.compareeexchange(ref _dictionary,updatedictionary,initialDictionary)!=initialDictionary);
}
}
这个实现没有实现IDictionary,因为那里有很多非必需的成员。但是,通过直接为所有非修改方法调用底层字典,并使用
ApplyAndChange(dict=>…)
包装所有修改方法,可以很容易地实现这一点


注意:就性能而言,与原始字典相比,此实现的Set、Add和Remove以及equal to Read和Contains性能更差。

如果您对阅读更感兴趣,您应该使用
ReaderWriterLockSlim

这是一个锁定原语,允许多个读卡器或一个写卡器在任何给定时间进入关键区域。当字典被多个线程读取时,这实际上不会导致性能下降,并且仅当线程尝试写入时才应用互斥

您可以这样实现它(为了简洁起见,我省略了大多数方法-我留下了
Add
作为编写器示例,而
Contains
作为读者示例):


如果所有非联锁操作都是原子操作,那么这将是线程安全的,但它们不是原子操作。在索引器
集中
,可以在
\u字典的行之间更改
\u字典。ContainsKey(key)
\u字典[key]=值。此解决方案不是线程安全的。我相信
ReaderWriterLockSlim
是一个更好的解决方案-您将获得大致相同的性能,但使用的方法不太容易出错。无锁代码很容易被破坏。@dcastro我试过ReaderWriterLockSlim,发现与无锁解决方案相比,性能大幅下降。不过,这可能是针对我的情况。我喜欢这个ReaderWriterLockSlim解决方案,它简单明了。
public class CustomDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    private readonly IDictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>(); 

    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        _lock.EnterReadLock();
        try
        {
            return _dictionary.Contains(item);
        }
        finally
        {
            _lock.EnterReadLock();
        }
    }

    public void Add(KeyValuePair<TKey, TValue> item)
    {
        _lock.EnterWriteLock();
        try
        {
            _dictionary.Add(item);
        }
        finally
        {
            _lock.ExitWriteLock();
        }
    }
}
    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        _lock.EnterReadLock();
        try
        {
            foreach (var entry in _dictionary)
                yield return entry;
        }
        finally
        {
            _lock.ExitReadLock();
        }
    }