嵌套 Parallel.For() 循环和文件创建问题

Nested Parallel.For() loops and file creation problems

我一直在研究 TPL 作为快速生成大量文件的方法 - 我在数据库中有大约 1000 万行,属于患者的事件,我想将其输出到他们自己的文本文件中,在位置 d:\EVENTS\PATIENTID\EVENTID.txt

我正在使用两个嵌套的 Parallel.ForEach 循环 - 外部循环用于检索患者列表,内部循环用于检索患者的事件并将其写入文件。

这是我正在使用的代码,目前还很粗糙,因为我只是想让事情正常运行。

DataSet1TableAdapters.GetPatientsTableAdapter ta = new DataSet1TableAdapters.GetPatientsTableAdapter();
List<DataSet1.GetPatientsRow> Pats = ta.GetData().ToList();

List<DataSet1.GetPatientEventsRow> events = null;

string patientDir = null;

System.IO.DirectoryInfo di = new DirectoryInfo(txtAllEventsPath.Text);
di.GetDirectories().AsParallel().ForAll((f) => f.Delete(true));

//get at the patients
Parallel.ForEach(Pats
        , new ParallelOptions() { MaxDegreeOfParallelism = 8 }
        , patient =>
{
    patientDir = "D:\Events\" + patient.patientID.ToString();

    //Output directory
    Directory.CreateDirectory(patientDir);
    events = new DataSet1TableAdapters.GetPatientEventsTableAdapter().GetData(patient.patientID).ToList();


    if (Directory.Exists(patientDir))
    {
        Parallel.ForEach(events.AsEnumerable()
            , new ParallelOptions() { MaxDegreeOfParallelism = 8 }
            , ev =>
            {
                List<DataSet1.GetAllEventRow> anEvent = 
                    new DataSet1TableAdapters.GetAllEventTableAdapter();    

                File.WriteAllText(patientDir + "\" + ev.EventID.ToString() + ".txt", ev.EventData);
            });
    }

});

我生成的代码运行速度非常快,但几秒钟后就会出现错误(其中生成了大约 6,000 个文件)。产生的错误是以下两种类型之一:

DirectoryNotFoundException: Could not find a part of the path 'D:\Events\PATIENTID\EVENTID.txt'.

每当产生此错误时,目录结构 D:\Events\PATIENTID\ 存在,因为在该目录中创建了其他文件。在进入第二个循环之前,if 条件检查 D:\Events\PATIENTID\ 是否存在。

The process cannot access the file 'D:\Events\PATIENTID\EVENTID.txt' because it is being used by another process.

发生此错误时,有时指示的文件存在或不存在。

因此,任何人都可以就为什么会产生这些错误提出任何建议。我也不明白,据我所知,它应该可以正常工作(而且确实可以工作一小会儿)。

From MSDN:

Use the Parallel Loop pattern when you need to perform the same independent operation for each element of a collection or for a fixed number of iterations. The steps of a loop are independent if they don't write to memory locations or files that are read by other steps.

Parallel.For 可以通过执行多线程来加快行的处理速度,但需要注意的是,如果使用不当,它将以程序的意外行为结束,就像您所拥有的那样以上。

出现以下错误的原因:

DirectoryNotFoundException: Could not find a part of the path 'D:\Events\PATIENTID\EVENTID.txt'.

可能是一个线程去写,目录不存在意味着另一个线程创建目录。通常,在进行并行处理时,可能会像我们所做的那样出现竞争条件 multi-threading,如果我们不使用适当的机制,如锁或监视器,那么我们最终会遇到这类问题。

因为你正在写文件,所以当尝试写入同一个文件时多个线程最终会出现你后来遇到的错误,即

The process cannot access the file 'D:\Events\PATIENTID\EVENTID.txt' because it is being used by another process.

因为一个线程已经在写入文件,所以那时其他线程将无法访问文件以写入文件。

我建议在这里使用普通循环而不是并行。