并行处理文件C#

时间:2014-04-28 21:29:49

标签: c# multithreading parallel-processing plinq

我有这个代码,它从文件中读取所有单词,并为每个唯一单词分配ID并将其添加到Dictionary中。我需要让它并行运行以提高应用程序的效率。我尝试过使用Parallel.ForEach而不是foreach但是,使用锁定将新单词和ID添加到字典中并不能提高效率...你们能告诉我这是什么来帮助我吗?我可以将此代码并行化的最佳方法?

    //static object locker = new object();
    string[] fnames; // Files are collected from a save file dialog
    Dictionary<string, IndexEntry> ID = new Dictionary<string, IndexEntry>(); 
    foreach (var fname in fnames)
        {

            string[] lines = File.ReadAllLines(fname);
            for (int i = 0; i < lines.Length; i++)
            {
                string[] Raw = Regex.Split(lines[i], @"\W+");

                for (int j = 0; j < Raw.Length; j++)
                {
                    string z = Raw[j];

                    if (!ID.ContainsKey(z))
                    {
                        ID.Add(z, new IndexEntry());
                    }
                }

3 个答案:

答案 0 :(得分:0)

如果多个线程访问此代码块,则首先考虑并发字典,这是一个线程安全的。这将为您实现锁定。

编辑:

http://msdn.microsoft.com/en-us/library/dd287191%28v=vs.110%29.aspx

答案 1 :(得分:0)

制作人/消费者模式是你的朋友。

你可以让一个线程读取文件,第二个线程插入到字典中,并且可能有第三个线程执行任何处理需要。第三个线程仅适用于在开始处理之前不必完全填充字典的情况(例如,如果足以读取给定的行)。

请注意,如果处理步骤微不足道,那么与单线程解决方案相比,您的收益将会降到最低。

查看Task Parallel Library。这非常适合这种类型的处理。

我使用这种模式来读取,处理和写入(到数据库)相当大的(1GB +)XML文档。

答案 2 :(得分:0)

问题是你最大的时间消费者正在阅读文件:

string[] lines = File.ReadAllLines(fname);

你一下子就把它啜饮了。你可能每个文件都有一个帖子,但我不认为他们会购买你很多,因为他们的I / O都争用同一个磁盘。尝试用更小的碎片做。这样的事可能对你有用:

static Dictionary<string,IndexEntry> ProcessFiles( IEnumerable<string> filenames )
{
  IEnumerable<string> words = filenames
                              .AsParallel()
                            //.WithMergeOptions( ParallelMergeOptions.NotBuffered )
                              .Select( x => ReadWordsFromFile(x) )
                              .SelectMany( x => x )
                              ;

  Dictionary<string,IndexEntry> index = new Dictionary<string,IndexEntry>() ;
  foreach( string word in words ) // would making this parallel speed things up? dunno.
  {
    bool found = index.ContainsKey(word) ;
    if ( !found )
    {
      index.Add( word, new IndexEntry() ) ;
    }
  }
  return index ;
}

static Regex rxWord = new Regex( @"\w+" ) ;
private static IEnumerable<string> ReadWordsFromFile( string fn )
{
  using( StreamReader sr = File.OpenText( fn ) )
  {
    string line ;
    while ( (line=sr.ReadLine()) != null )
    {
      for ( Match m = rxWord.Match(line) ; m.Success ; m = m.NextMatch() )
      {
        yield return m.Value ;
      }
    }
  }
}