1

以下是处理大约 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);
    }
4

2 回答 2

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);
    }
}
于 2013-05-07T09:05:09.697 回答
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));
于 2013-05-07T09:36:05.697 回答