Parallel.ForEach中的File.Copy

Mik*_*ike 8 c# parallel-processing file-copying

我正在尝试创建一个目录并在一个文件中复制一个文件(pdf)Parallel.ForEach.

下面是一个简单的例子:

    private static void CreateFolderAndCopyFile(int index)
    {
        const string sourcePdfPath = "c:\\testdata\\test.pdf";
        const string rootPath = "c:\\testdata";

        string folderDirName = string.Format("Data{0}", string.Format("{0:00000000}", index));

        string folderDirPath = rootPath + @"\" + folderDirName;

        Directory.CreateDirectory(folderDirPath);

        string desPdfPath = folderDirPath + @"\" + "test.pdf";

        File.Copy(sourcePdfPath, desPdfPath, true);

    }
Run Code Online (Sandbox Code Playgroud)

上述方法创建一个新文件夹并将pdf文件复制到新文件夹.它创建了这个目录树:

TESTDATA
  -Data00000000
      -test.pdf
  -Data00000001
      -test.pdf
....
  -Data0000000N
      -test.pdf
Run Code Online (Sandbox Code Playgroud)

我试着CreateFolderAndCopyFileParallel.ForEach循环中调用该方法.

    private static void Func<T>(IEnumerable<T> docs)
    {
        int index = 0;
        Parallel.ForEach(docs, doc =>
                                   {
                                       CreateFolderAndCopyFile(index);
                                       index++;
                                   });
    }
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时,它完成以下错误:

该进程无法访问文件'c:\ testdata\Data00001102\test.pdf',因为它正由另一个进程使用.

但首先它创建了1111个新文件夹,并在我收到此错误之前复制了test.pdf约1111次.

是什么导致了这种行为以及如何解决?

编辑:

上面的代码是玩具样本,对于硬编码字符串很抱歉 结论:并行方法很慢.

明天我尝试了一些方法,如何在C#中编写超快文件流代码?.

特别是:http: //designingefficientsoftware.wordpress.com/2011/03/03/efficient-file-io-from-csharp/

Dav*_*nan 18

您没有同步访问权限index,这意味着您正在进行竞争.这就是你有错误的原因.为了便于说明,您可以通过使用来避免竞争并保持此特定设计Interlocked.Increment.

private static void Func<T>(IEnumerable<T> docs)
{
    int index = -1;
    Parallel.ForEach(
        docs, doc =>
        {
            int nextIndex = Interlocked.Increment(index);
            CreateFolderAndCopyFile(nextIndex);
        }
    );
}
Run Code Online (Sandbox Code Playgroud)

然而,正如其他人所说的那样,ForEach提供循环索引的替代过载显然是解决这个特定问题的一个更清晰的解决方案.

但是当你使它工作时,你会发现复制文件是IO绑定而不是处理器绑定,我预测并行代码将比串行代码慢.

  • 您不会比系统提供的文件复制例程做得更好. (2认同)

use*_*116 7

您的增量操作index是可疑的,因为它不是线程安全的.如果您将操作更改为Console.WriteLine("{0}", index++)您将看到此行为.

相反,您可以使用Parallel.ForEach带循环索引的重载:

private static void Func<T>(IEnumerable<T> docs)
{
    // nb: index is 'long' not 'int'
    Parallel.ForEach(docs, (doc, state, index) =>
                            {
                                CreateFolderAndCopyFile(index);
                            });
}
Run Code Online (Sandbox Code Playgroud)