1

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

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

  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# 开发人员,他告诉我这可能是任务已知问题,有时会陷入僵局。是否可以使用另一个 Class 而不是 Task ?

4

1 回答 1

0

您不应该使用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(); 
}
于 2013-08-01T10:18:23.747 回答