2015-09-20 42 views
1

我有以下的代码,开始作为一个孩子的任务,以获得给定目录下的所有文件,并做一些事情上的主题和调用事件的每个文件,提醒父任务:等待子任务,真正compelete

internal class FileFinder 
{ 
    private readonly string _fileFormat; 

    public delegate void FileFoundDelegate(string filePath); 

    public event FileFoundDelegate OnFileFound; 

    public FileFinder(string fileFormat) 
    { 
     _fileFormat = fileFormat; 
    } 

    public bool Start(CancellationToken cancellationToken, string directory) 
    { 
     try 
     { 
      if (OnFileFound == null) 
       return false; 

      var foundedFiles = new ThreadLocal<IEnumerable<string>>(); 
      try 
      { 
       foundedFiles.Value = Directory.EnumerateFiles(directory, _fileFormat, SearchOption.AllDirectories) 
        .AsParallel(); 
      } 
      catch (Exception ex) 
      { 
       Debug.WriteLine("Parallel : " + ex.Message); 
      } 

      foreach (var file in foundedFiles.Value) 
      { 
       if (cancellationToken.IsCancellationRequested) 
        return true; 

       // Call file found event with normalized file name 
       OnFileFound?.Invoke(file); 
      } 

      return true; 
     } 
     catch (Exception ex) 
     { 
      Common.DebugLog(System.Reflection.MethodBase.GetCurrentMethod().Name, 
       ex.InnerException?.Message ?? ex.Message); 
      return false; 
    } 
    } 
} 

,并使用名为撒母任务,分散经营的5 seprate任务FileFinder是主题之一调用它:

internal class Scatter 
    { 
     private readonly CancellationToken _cancellationToken; 
     private readonly string _directory; 
     private readonly string _fileFormat; 

     private FileFinder _emailFinder; 

     public Scatter(CancellationToken cancellationToken, string directory, string fileFormat) 
     { 
      _cancellationToken = cancellationToken; 
      _directory = directory; 
      _fileFormat = fileFormat; 
     } 

     public Task Start() 
     { 
      try 
      { 
       return Task.Factory.StartNew(StartProc, 
        TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning); 
      } 
      catch (Exception) 
      { 
       return null; 
      } 
     } 

     private void StartProc() 
     { 
      try 
      { 
       // Find pdf files 
       _emailFinder = new FileFinder(_fileFormat); 
       _emailFinder.OnFileFound += FileFound; 
       Task.Factory.StartNew(() => _emailFinder.Start(_cancellationToken, _directory), 
        TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning); 
      } 
      catch (Exception ex) 
      { 
       Common.DebugLog(System.Reflection.MethodBase.GetCurrentMethod().Name, ex.InnerException.Message); 
      } 
     } 

     private void FileFound(string filePath) 
     { 
      Debug.WriteLine("File Found"); 
     } 
    } 

最后一个主任务运行单独分散的每个目录:

internal class Master 
    { 
     private readonly CancellationToken _cancellationToken; 

     internal delegate void ParseFinish(); 
     public event ParseFinish OnParseFinish; 

     public Master(CancellationToken cancellationToken) 
     { 
      _cancellationToken = cancellationToken; 
     } 

     public bool Start(List<string> targetDirectories, string fileFormat) 
     { 
      try 
      { 
       Task.Factory.StartNew(() => StartProc(targetDirectories, fileFormat), _cancellationToken); 
       return true; 
      } 
      catch (Exception ex) 
      { 
       Common.DebugLog(System.Reflection.MethodBase.GetCurrentMethod().Name, 
        ex.InnerException?.Message ?? ex.Message); 
       return false; 
      } 
     } 

     private bool StartProc(List<string> directories, string fileFormat) 
     { 
      try 
      { 
       List<Task> targetScatterList = new List<Task>(); 

       foreach (string dir in directories) 
       { 
        var scatter = new Scatter(_cancellationToken,dir, fileFormat); 

        targetScatterList.Add(scatter.Start()); 
       } 

       // Wait for finish all tasks & call parse finish event 
       Task.WaitAll(targetScatterList.ToArray()); 
       OnParseFinish?.Invoke(); 

       return true; 
      } 
      catch (Exception ex) 
      { 
       Common.DebugLog(System.Reflection.MethodBase.GetCurrentMethod().Name, 
        ex.InnerException?.Message ?? ex.Message); 
       return false; 
      } 
     } 
    } 

我有主任务等待所有目录的任务完成并且不涉及应用程序主线程。从主线程

主任务调用是这样的:

List<string> directoryList = ListBox1.Items.Cast<string>().ToList(); 

    // Create cancelation token 
    _cancellationTokenSource = new CancellationTokenSource(); 
    _cancellationToken = _cancellationTokenSource.Token; 

    // Start master task that populate new task for each target 
    var masterTask= new Master(_cancellationToken); 
    masterTask.OnParseFinish += ParseFinish; 
    masterTask.Start(directoryList, tbFileFormat.Text); 

我有样书导演287198个PDF文件时,的FileFound事件称为项目(287170,287182,287146和等)的不同的运行随机时间并且不会迭代所有创建的项目。

小文件列表它剂量没有表现出很大的差异

我觉得父任务去完成和孩子立即去杀人。

有什么想法?

谢谢。

+0

subscription.Dispose(); 

如果你想知道它何时完成,只是这样做它,你可以做一个'Console.WriteLine(createdFiles.Value.Length)'来确保枚举本身是完整的吗? –

+0

你在你的'StartProc'方法中开始一个任务,不要等待它。你提到你的主线程正在等待父任务,但你的父任务不在等待子任务。 –

+0

@EdT不正确 - 如果子任务以AttachedToParent标志开始,等待父任务只有在所有连接的子任务完成后才会返回。 – Evk

回答

2

你的代码是我见过的最惊人的过度编码之一。

下面是使用Microsoft的Reactive Framework(NuGet“Rx-Main”)编写的相同代码。

var query = 
    from dir in directoryList.ToObservable() 
    from file in 
      Directory.EnumerateFiles(dir, tbFileFormat.Text, SearchOption.AllDirectories) 
    select file; 

var subscription = query.Subscribe(file => 
{ 
    ParseFinish(file); 
}); 

就是这样。这一切都使用后台线程处理。它摆脱了所有这些课程,只是做你需要的工作。

如果你想通过取消中途,只是这样做:只是为了赫克

var subscription = query.Subscribe(file => 
{ 
    ParseFinish(file); 
},() => 
{ 
    /* Handle the query is finished here */ 
}); 
+0

非常感谢,但我也想知道我的代码问题。 –

+0

我有几个任务在Scatter和FileFinder是主题之一,我想手动控制所有的操作。 –

+0

@MojtabaTajik - 我认为你现有代码的问题是'Task.Factory.StartNew(()=> StartProc(targetDirectories,fileFormat),_cancellationToken)'行。您正在开始一项新任务,但您没有对返回的任务对象进行任何操作。相反,你要立即返回一个“布尔”。 – Enigmativity