如果我使用Parallel.ForEach(),为什么有些文件会被遗漏?

时间:2013-05-07 08:54:46

标签: c# multithreading

以下是处理大约10000个文件的代码。

var files = Directory.GetFiles(directorypath, "*.*", SearchOption.AllDirectories).Where(
                    name => !name.EndsWith(".gif") && !name.EndsWith(".jpg") && !name.EndsWith(".png")).ToList();
Parallel.ForEach(files,Countnumberofwordsineachfile);

Countnumberofwordsineachfile函数将每个文件中的单词数打印到文本中。 每当我实现Parallel.ForEach()时,每次处理时我都会错过4-5个文件。 任何人都可以建议为什么会这样?

  public void Countnumberofwordsineachfile(string filepath)
    {
        string[] arrwordsinfile = Regex.Split(File.ReadAllText(filepath).Trim(), @"\s+");
        Charactercount = Convert.ToInt32(arrwordsinfile.Length);
        filecontent.AppendLine(filepath + "=" + Charactercount);
    }

2 个答案:

答案 0 :(得分:4)

fileContent可能不是线程安全的。因此,如果两个(或更多)任务试图在同一时间附加到它上面,那么另一个将不会。您需要记住锁定共享的部分,或者不使用共享数据。

这可能是您代码最简单的解决方案。锁定,同步访问(其他任务必须排队以访问锁定部分)因此它会减慢算法的速度,但由于这个数字非常短,因此计算单词很可能是那么它实际上不会这是一个很大的问题。

private object myLock = new object();
public void Countnumberofwordsineachfile(string filepath)
{
    string[] arrwordsinfile = Regex.Split(File.ReadAllText(filepath).Trim(), @"\s+");
    Charactercount = Convert.ToInt32(arrwordsinfile.Length);
    lock(myLock)
    {
        filecontent.AppendLine(filepath + "=" + Charactercount);
    }
}

答案 1 :(得分:1)

原因已经找到,这是另一种实现方式:

//Parallel.ForEach(files,Countnumberofwordsineachfile);
var fileContent = files
        .AsParallel()
        .Select(f=> f + "=" + Countnumberofwordsineachfile(f));

这需要一个更有用的count方法设计:

// make this an 'int' function, more reusable as well
public int Countnumberofwordsineachfile(string filepath)
{ ...; return characterCount; }

但是请注意,并行对你来说没有多大帮助,你的主要功能(ReadAllText)是I / O绑定的,所以你很可能会看到使用AsParallel()时出现性能下降。

更好的选择是使用Directory.EnumerateFiles,然后在没有并行性的情况下收集结果:

var files = Directory.EnumerateFiles(....);
var fileContent = files
         //.AsParallel()
         .Select(f=> f + "=" + Countnumberofwordsineachfile(f));