0

我是一名初级程序员,我正在尝试解决一项任务。使用 c# .net 4.0 我在文件夹中运行,选择所有 *.xml 文件,并将每个文件写入具有新扩展名 *.bin 的新文件夹。对于编写之前的每个文件,我正在应用由另一个程序员编写的算法,我不知道它的实现。

所以我读取 *.xml 文件,将其反序列化并将其写入新的 *.bin 文件。当我没有使用并行编程时,我有 1 分钟的时间来处理 2000 个文件。现在我决定使用Task应用并行编程。现在我为每个文件创建新任务(所有处理(读取-反序列化-写入)都在一个任务中),现在我有 40 秒。但我认为并行编程帮助我将时间减少到 25-30 秒。

请给出您的意见,我做错了什么以及我必须如何意识到这一点。谢谢。

byte[] buffer;
using (Stream stream = new FileInfo(file).OpenRead())
{
    buffer = new byte[stream.Length];
    stream.Read(buffer, 0, (int)stream.Length);
}

foreach (var culture in supportedCultures)
{
    CultureInfo currentCulture = culture;
    Tasks.Add(Task.Factory.StartNew(() =>
    {
        var memoryStream = new MemoryStream(buffer);
        Task<object> serializeTask = Task.Factory.StartNew(() =>
        {
            return typesManager.Load(memoryStream, currentCulture);
        }, TaskCreationOptions.AttachedToParent);

        string currentOutputDirectory = null;
        if (outputDirectory != null)
        {
            currentOutputDirectory = outputDirectory.Replace(PlaceForCultureInFolderPath,
                                                                 currentCulture
                                                                     .ToString());
            Directory.CreateDirectory(currentOutputDirectory);
        }

        string binFile = Path.ChangeExtension(Path.GetFileName(file), ".bin");
        string binPath = Path.Combine(
            currentOutputDirectory ?? Path.GetDirectoryName(file),
            binFile);

        using (FileStream outputStream = File.OpenWrite(binPath))
        {
            try
            {
                new BinaryFormatter().Serialize(outputStream,serializeTask.Result);
            }
            catch (SerializationException e)
            {
                ReportCompilationError(e.Message, null);
            }
        }
    }));
}
4

3 回答 3

3

在没有看到代码或不知道任务真正在做什么的情况下,我们所能做的就是提供一些相当一般的建议和诊断。

您的代码是受 CPU 限制还是受 IO 限制?(您应该能够通过查看性能监视器并查看运行代码时 CPU 的繁忙程度来判断这一点。)

如果您的代码是 IO 绑定的,并且如果您在单个物理非 SSD 驱动器上有多个文件,那么并行工作可能会使情况变得更糟,因为您会迫使驱动器头不断打点这个地方。

如果您的代码受 CPU 限制,那么并行化应该会有所帮助(因为这些听起来像是独立的任务) - 同样,您应该能够通过先运行代码而不进行并行化然后再进行并行化来判断这一点,在这两种情况下都查看 CPU 图. 您会期望在串行版本中,一次只有一个 CPU 处于“忙碌”状态,而在并行版本中,所有 CPU 都应该处于忙碌状态。

于 2012-12-06T08:15:24.647 回答
2

任务工厂

var task1 = Task.Factory.StartNew(() =>
    {
       //some oepratation
    });
     var task2 = Task.Factory.StartNew(() =>
    {
       //some operations
    });
    Task.WaitAll(task1, task2);

但这并不能保证每个任务都有一个新线程,因为它使用可用线程并且只是调度作业或将任务分配给任何可用的线程。因此,我建议你使用Parallel.ForEach

var options = new ParallelOptions { MaxDegreeOfParallelism = 2 // or more };
Parallel.ForEach ( list, options, a=> { } );

http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.foreach.aspx

于 2012-12-06T08:17:25.543 回答
1

第一的。不能保证 TPL 会对性能造成任何影响。
正如 Jon 所说,写入 HDD 会降低性能,除非操作系统缓存这些文件以供以后顺序写入。绝对缓存大小有其限制。

第二。默认调度程序面向利用 CPU 内核,因此有可能只有几个任务被并行处理,而其他任务则在队列中等待。您可以通过显式设置ParallelOptions.MaxDegreeOfParallelism或调用WidthDegreeOfParallelism()查询来更改此默认值。仍然是调度程序决定有多少任务并行运行。

.net 中有一本关于多线程的不错的免费书籍

于 2012-12-06T08:48:35.973 回答