Cha*_*les 4 c# performance ienumerable multithreading caching
[编辑]
新的Reactive Framework使用System.Linq.EnumerableEx.MemoizeAll()扩展方法解决了下面列出的问题.
在内部,MemoizeAll()使用a System.Linq.EnumerableEx.MemoizeAllEnumerable<T>(在System.Interactive程序集中找到),类似于my ThreadSafeCachedEnumerable<T>(sorta).
这是一个非常人为的例子,它非常缓慢地打印出Enumerable(数字1-10)的内容,然后第二次快速打印内容(因为它缓存了值):
// Create an Enumerable<int> containing numbers 1-10, using Thread.Sleep() to simulate work
var slowEnum = EnumerableEx.Generate(1, currentNum => (currentNum <= 10), currentNum => currentNum, previousNum => { Thread.Sleep(250); return previousNum + 1; });
// This decorates the slow enumerable with one that will cache each value.
var cachedEnum = slowEnum.MemoizeAll();
// Print the numbers
foreach (var num in cachedEnum.Repeat(2))
{
    Console.WriteLine(num);
}
[/编辑]
你好多线程大师,
我创建了ThreadSafeCachedEnumerable类,旨在提高长时间运行的重用查询的性能.我们的想法是从IEnumerable获取一个枚举器,并在每次调用MoveNext()时将项添加到缓存中.以下是我目前的实施:
/// <summary>
/// Wraps an IEnumerable<T> and provides a thread-safe means of caching the values."/>
/// </summary>
/// <typeparam name="T"></typeparam>
class ThreadSafeCachedEnumerable<T> : IEnumerable<T>
{
    // An enumerator from the original IEnumerable<T>
    private IEnumerator<T> enumerator;
    // The items we have already cached (from this.enumerator)
    private IList<T> cachedItems = new List<T>();
    public ThreadSafeCachedEnumerable(IEnumerable<T> enumerable)
    {
        this.enumerator = enumerable.GetEnumerator();
    }
    #region IEnumerable<T> Members
    public IEnumerator<T> GetEnumerator()
    {
        // The index into the sequence
        int currentIndex = 0;
        // We will break with yield break 
        while (true)
        {
            // The currentIndex will never be decremented,
            // so we can check without locking first
            if (currentIndex < this.cachedItems.Count)
            {
                var current = this.cachedItems[currentIndex];
                currentIndex += 1;
                yield return current;
            }
            else
            {
                // If !(currentIndex < this.cachedItems.Count),
                // we need to synchronize access to this.enumerator
                lock (enumerator)
                {
                    // See if we have more cached items ...
                    if (currentIndex < this.cachedItems.Count)
                    {
                        var current = this.cachedItems[currentIndex];
                        currentIndex += 1;
                        yield return current;
                    }
                    else
                    {
                        // ... otherwise, we'll need to get the next item from this.enumerator.MoveNext()
                        if (this.enumerator.MoveNext())
                        {
                            // capture the current item and cache it, then increment the currentIndex
                            var current = this.enumerator.Current;
                            this.cachedItems.Add(current);
                            currentIndex += 1;
                            yield return current;
                        }
                        else
                        {
                            // We reached the end of the enumerator - we're done
                            yield break;
                        }
                    }
                }
            }
        }
    }
    #endregion
    #region IEnumerable Members
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
    #endregion
}
我只是"锁定(this.enumerator)"当没有更多的项目似乎在缓存中,以防另一个线程即将添加另一个项目(我假设从两个线程调用this.enumerator上的MoveNext()一个坏主意).
检索以前缓存的项目时性能很好,但是当第一次获取多个项目时(由于持续锁定),它开始受到影响.有关提高性能的建议吗?
谢谢!
一些建议:
Dictionary或HashSet.类似地,可以在调用之间移除项目,使高速缓存无效.