3

我有一个文件列表,其中每个文件都包含一个Foo数据列表。现在,同一段 Foo 数据(例如Id = 1)可能存在于多个文件中,但最近的一段数据会覆盖现有的。

我只是将每条数据读入内存集合中。

if !cache.HasKey(foo.Id) then Add    
else cache[foo.Id].UpdatedOn < foo.UpdatedOn then Update  
else do nothing

当我阅读文件时(因为有几个 em),我也在使用Parallel.ForEach(files, file => { .. });

我不确定我是怎么做到的。

我正在考虑使用 aConcurrentDictionary但我不确定如何AddOrUpdate使用where子句来做事。

有什么建议么?

4

2 回答 2

4

您可以使用 a ConcurrentDictionary,如下所示:

dictionary.AddOrUpdate(foo.Id, foo, (id, existing) => 
    existing.UpdatedOn < foo.UpdatedOn ? foo : existing);

由于下面评论中的讨论,我将解释为什么这里没有竞争条件。这篇MSDN 文章讨论了价值工厂的运行方式,并提到:

因此,不能保证 GetOrAdd 返回的数据与线程的 valueFactory 创建的数据相同。

这是有道理的,因为并发字典的设计者不希望用户代码将字典锁定不知道多久,使其无用。相反,AddOrUpdate它在两个嵌套循环中运行。这是一些伪代码:

do { 
   while (!TryGetValue(key, out value))
       if (TryAdd(key, addValue)) return;
   newValue = updateValueFactory(key, value);
} while (TryUpdate(key, newValue, value));

TryUpdate获取特定存储桶的锁,将当前值与检索到的值进行比较,并且仅当它们匹配时才执行更新。如果失败,外部循环再次发生,TryGetValue返回最新值,再次调用值工厂,依此类推。

因此可以保证,如果更新成功,值工厂将始终具有最新的值。

于 2014-02-19T10:39:56.517 回答
0

该方法中的有趣行为ConcurrentDictionary.AddOrUpdate

class Program
{
    static void Main( string[] args )
    {
        var cd = new System.Collections.Concurrent.ConcurrentDictionary<int, int>();

        var a = 0;
        var b = 1;
        var c = 2;

        cd[ 1 ] = a;

        Task.WaitAll(
            Task.Factory.StartNew( () => cd.AddOrUpdate( 1, b, ( key, existingValue ) =>
                {
                    Console.WriteLine( "b" );
                    if( existingValue < b )
                    {
                        Console.WriteLine( "b update" );
                        System.Threading.Thread.Sleep( 2000 );
                        return b;
                    }
                    else
                    {
                        Console.WriteLine( "b no change" );
                        return existingValue;
                    }
                } ) ),

            Task.Factory.StartNew( () => cd.AddOrUpdate( 1, c, ( key, existingValue ) =>
            {
                Console.WriteLine( "c start" );
                if( existingValue < c )
                {
                    Console.WriteLine( "c update" );
                    return c;
                }
                else
                {
                    Console.WriteLine( "c no change" );
                    return existingValue;
                }
            } ) ) );

        Console.WriteLine( "Value: {0}", cd[ 1 ] );

        var input = Console.ReadLine();
    }
}

结果:

ConcurrentDictionary.AddOrUpdate 测试输出

于 2014-02-19T11:36:03.627 回答