【问题标题】:Control number of threads (not Task)控制线程数(不是任务)
【发布时间】:2013-08-01 08:49:20
【问题描述】:

我有一个文件列表,我需要运行的每个文件(PCAP 文件 - 传输数据包)都有自己的运行时间。

因为我想要处理超过 1 个并行文件的选项,所以我使用这个函数来获取 IEnumerable<string> source 和最大并行线程数:

  public void doWork(IEnumerable<string> _source, int parallelThreads)
    {
        _tokenSource = new CancellationTokenSource();
        var token = _tokenSource.Token;
        Task.Factory.StartNew(() =>
        {
            try
            {
                Parallel.ForEach(_source,
                    new ParallelOptions
                    {
                        MaxDegreeOfParallelism = parallelThreads //limit number of parallel threads 
                    },
                    file =>
                    {
                        if (token.IsCancellationRequested)
                            return;
                        //process my file...
                    });
            }
            catch (Exception)
            { }

        }, _tokenSource.Token).ContinueWith(
                t =>
                {
                    //finish all the list...
                }
            , TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
            );
    }

例如,如果我有 10 个文件的列表并且我的最大并行线程数是 4,那么我的程序开始并行传输 4 个文件,并且在第一个文件完成后,另一个文件自动启动,如果我传输所有文件,这很好用我的清单 1 次。

在添加了循环播放所有列表的选项后,我遇到了一个问题,例如,如果我想播放所有列表两次,则在第一个循环结束后第二个开始,在第一个文件完成后在此循环中完成所有UI 卡住了,没有响应。 我和朋友谈过他是 C# 开发人员,他告诉我这可能是任务已知问题,有时会陷入僵局。 是否可以使用另一个类而不是任务?

【问题讨论】:

  • 1.对异常做一些事情,它可能会给你一个很好的提示,出了什么问题。 2、UI卡住的时候,是主线程的问题。因此,请添加您遗漏的代码,因为我猜问题会出现在某个地方。
  • 从来没有听说过这个“任务已知问题,有时会陷入僵局”,但我看到人们使用(等待)来自不同任务的共享资源导致死锁。
  • 我可以有一个没有任务的代码示例吗?

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


【解决方案1】:

您不应该将Parallel.ForEach 用于文件 IO。这不是 cpu 密集型任务。您应该能够一个接一个地开始所有任务。这样,您将使用更少的线程,并且您的应用程序将更具可扩展性。

更新示例

public static void doWork(IEnumerable<string> _source, int numThreads)
{
    var _tokenSource = new CancellationTokenSource();

    List<Task> tasksToProcess = new List<Task>();
    foreach (var file in _source)
    {
        tasksToProcess.Add( Task.Factory.StartNew(() =>
                              {
                                  Console.WriteLine("Processing " + file );
                                  //do file operation
                                  Thread.Sleep(5000);

                                  Console.WriteLine("Finished Processing " + file);
                              },
                          _tokenSource.Token));

        if(tasksToProcess.Count % numThreads == 0)
        {
            Console.WriteLine("Waiting for tasks");

            Task.WaitAll(tasksToProcess.ToArray(), _tokenSource.Token);

            Console.WriteLine("All tasks finished");   
            tasksToProcess.Clear();
        }
    }             
}

void Main()
{
    var fileList = Enumerable.Range(0, 100).Select (e => "file" + e.ToString());
    doWork(fileList, 4);

    Console.ReadLine(); 
}

【讨论】:

  • 我可以举个例子吗? (包括如何控制并发线程数)
  • 我在答案中添加了一个简单的示例。将Thread.Sleep 替换为您需要进行的任何文件处理
  • @user2214609 正如 Ned 所说,您正在进行 I/O 工作,而不是 CPU 密集型计算。因此,无论如何,您的线程大部分时间都将处于空闲状态。 .net 线程池对此非常聪明,会自动为您管理线程数量和并发程度。那么为什么要精确控制线程数呢?
  • @user2214609 澄清一下我之前的评论:任务不等同于线程。在这种情况下,线程将比任务(即文件)少得多。所以如果你想控制某些东西,你应该谈论并行度而不是线程。
  • 但在你的例子中我无法控制文件的并发数
猜你喜欢
  • 1970-01-01
  • 2017-04-10
  • 2013-05-30
  • 2011-04-21
  • 2013-09-01
  • 2011-09-29
  • 2019-12-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多