【问题标题】:How can I use class Task for parallel proccess如何使用类 Task 进行并行处理
【发布时间】:2012-12-06 08:10:28
【问题描述】:

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

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

请告诉您的 cmets 我做错了什么以及我必须如何意识到这一点。谢谢。

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);
            }
        }
    }));
}

【问题讨论】:

  • 请提供一些代码

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


【解决方案1】:

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

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

如果您的代码是 IO 绑定的,并且如果您在单个物理非 SSD 驱动器上有多个文件,那么并行工作可能会使情况变得更糟,因为您会强制驱动器磁头保持到处都是。

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

【讨论】:

  • 乔恩,谢谢 - 我注意到,与并行版本相比,处理器的每个核心都加载了 70-80%。这还不够,但也许你是对的,硬盘不能这么快写这么多文件。
【解决方案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

【讨论】:

    【解决方案3】:

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

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

    有一个不错的免费 book 介绍 .net 中的多线程

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多