C#中的并行编程

我有兴趣了解C#.NET中的并行编程(不是所有要知道的东西,而是基础知识,也许是一些好的实践),因此我决定重新编程我的一个名为ImageSyncer的旧程序。 ImageSyncer是一个非常简单的程序,它所做的只是扫描一个文件夹,找到以.jpg结尾的所有文件,然后根据它们的拍摄日期计算文件的新位置(解析xif数据,或者其他它被称为)。 在生成位置之后,程序检查该位置的任何现有文件,如果存在,则查看要复制的文件的最后写入时间和文件“以其方式”。 如果它们相等,则跳过该文件。 如果不是,则创建并匹配两个文件的md5校验和。 如果没有匹配,则要为要复制的文件指定要复制到的新位置(例如,如果要将其复制到“C:\ test.jpg”,则将其复制到“C:\ test(1)”。 jpg“而不是”。 此操作的结果将填充到包含两个字符串的struct-type队列中,即原始文件和要将其复制到的位置。 然后迭代该队列,直到它为空并且复制文件。

换句话说,有4个操作:

1. Scan directory for jpegs 2. Parse files for xif and generate copy-location 3. Check for file existence and if needed generate new path 4. Copy files 

因此,我想重写这个程序,使其成为并列,并能够同时执行多个操作,我想知道实现这一目标的最佳方法是什么。 我想出了两个我能想到的不同模型,但它们中的任何一个都没有任何好处。 第一个是并行化旧程序的4个步骤,以便当要执行第一步时,它在几个线程上完成,并且当完成整个步骤1时,开始步骤2。 另一个(我发现它更有趣,因为我不知道如何做到这一点)是创建一种工作者和消费者模型,所以当一个线程完成步骤1时,另一个接管并执行第2步对象(或类似的东西)。 但如上所述,我不知道这些是否有任何好的解决方案。 另外,我对并行编程一点都不太了解。 我知道如何创建一个线程,以及如何使它执行一个以对象作为唯一参数的函数,并且我也曾经使用过BackgroundWorker类,但我对它们中的任何一个都不熟悉。

任何输入将不胜感激。

几个选项:

  • 并行LINQ : 在多核处理器上运行查询

  • 任务并行库 (TPL): 优化多核机器的托管代码

  • 如果您对基本线程原语和概念感兴趣: 在C#中进行线程处理

[但正如@John Knoeller指出的那样,你给出的例子可能是顺序I / O界限]

这是我用于C#线程的参考: http : //www.albahari.com/threading/

作为单个PDF: http : //www.albahari.com/threading/threading.pdf

对于你的第二种方法:

我曾经参与过一些生产者/消费者multithreading应用程序,其中每个任务都是一些永远循环的代码。 外部“初始化程序”为每个任务启动一个单独的线程,并为每个任务初始化一个EventWaitHandle。 对于每个任务,都是一个可用于生成/使用输入的全局队列。

在您的情况下,您的外部程序会将每个目录添加到Task1的队列中,并为Task1设置EventWaitHandler。 任务1将从其EventWaitHandler中“唤醒”,获取其队列中的目录计数,然后当计数大于0时,从队列中获取目录,扫描所有.jpgs,并添加每个.jpg位置到第二个队列,并为任务2设置EventWaitHandle。任务2读取其输入,处理它,将其转发到任务3的队列…

让所有锁定正常工作可能有点痛苦(我基本上锁定了对队列的任何访问,甚至像获取计数一样简单)。 .NET 4.0应该具有自动支持没有锁的生产者/消费者队列的数据结构。

有趣的问题。 我提出了两种方法。 第一个基于PLinq,第二个基于te Rx Framework。

第一个并行迭代文件。 第二个异步生成目录中的文件。

以下是它在简化版本中的样子(第一种方法确实需要.Net 4.0,因为它使用了PLinq)

 string direcory = "Mydirectory"; var jpegFiles = System.IO.Directory.EnumerateFiles(direcory,"*.jpg"); // -- PLinq -------------------------------------------- jpegFiles .AsParallel() .Select(imageFile => new {OldLocation = imageFile, NewLocation = GenerateCopyLocation(imageFile) }) .Do(fileInfo => { if (!File.Exists(fileInfo.NewLocation ) || (File.GetCreationTime(fileInfo.NewLocation)) != (File.GetCreationTime(fileInfo.NewLocation))) File.Copy(fileInfo.OldLocation,fileInfo.NewLocation); }) .Run(); // ----------------------------------------------------- //-- Rx Framework --------------------------------------------- var resetEvent = new AutoResetEvent(false); var doTheWork = jpegFiles.ToObservable() .Select(imageFile => new {OldLocation = imageFile, NewLocation = GenerateCopyLocation(imageFile) }) .Subscribe( fileInfo => { if (!File.Exists(fileInfo.NewLocation ) || (File.GetCreationTime(fileInfo.NewLocation)) != (File.GetCreationTime(fileInfo.NewLocation))) File.Copy(fileInfo.OldLocation,fileInfo.NewLocation); },() => resetEvent.Set()); resetEvent.WaitOne(); doTheWork.Dispose(); // -----------------------------------------------------