如何使用类Task进行并行处理

时间:2012-12-06 08:10:28

标签: c# multithreading c#-4.0 task-parallel-library task

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

所以我读取* .xml文件,反序列化并将其写入新的* .bin文件。当我没有使用并行编程时,我有2000分钟的文件。现在我决定使用任务来应用并行编程。现在我为每个文件创建新任务(所有进程(read-deserialize-write)都在一个任务中),现在我有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);
            }
        }
    }));
}

3 个答案:

答案 0 :(得分:3)

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

你的代码是CPU绑定的还是IO绑定的? (您应该能够通过查看性能监视器来了解这一点,并了解运行代码时CPU的繁忙程度。)

如果您的代码是IO绑定的,并且如果您在单个物理非SSD驱动器上有多个文件,那么将工作并行放置可能会使其变得更糟,因为您迫使驱动器头保持不变遍布整个地方。

如果你的代码是CPU绑定的,那么并行化应该正在帮助(因为它们听起来像独立的任务) - 再次,你应该能够通过先运行你的代码而没有并行化然后< em> with 并行化,在两种情况下查看CPU图。您将期望在串行版本中,一次只有一个CPU“忙”,而在并行版本中,所有CPU都应该忙。

答案 1 :(得分:2)

Task.Factory

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

答案 2 :(得分:1)

首先。无法保证TPL会影响性能 正如乔恩所说,写入硬盘可以降低性能,除非操作系统缓存这些文件以供以后顺序写入。绝对缓存大小有其局限性。

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

在.net

中有一个关于多线程的免费book