等待子任务真正完成
Wait for child task to really 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;
}
}
}
并使用名为 Scatter 的父任务调用它,分散 运行 5 个单独的任务,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);
我在示例书籍目录中有 287,198 个 PDF 文件,FileFound 事件在不同 运行 项目(287170、287182、287146 等)中随机调用,并且不迭代所有已创建的项目。
在小文件列表中它没有显示出很大的区别
我认为父任务完成,子任务立即杀人。
有什么想法吗?
谢谢。
您的代码是我见过的代码量最大的代码之一。
这是使用 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);
});
就是这样。这一切都是使用后台线程处理的。它摆脱了所有这些 类,只做你需要的工作。
如果你想中途取消,就这样做:
subscription.Dispose();
如果您想知道它何时完成,只需执行以下操作:
var subscription = query.Subscribe(file =>
{
ParseFinish(file);
}, () =>
{
/* Handle the query is finished here */
});
我有以下代码作为子任务启动,以获取给定目录中的所有文件并根据主题执行某些操作,并为每个文件调用事件以提醒父任务:
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;
}
}
}
并使用名为 Scatter 的父任务调用它,分散 运行 5 个单独的任务,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);
我在示例书籍目录中有 287,198 个 PDF 文件,FileFound 事件在不同 运行 项目(287170、287182、287146 等)中随机调用,并且不迭代所有已创建的项目。
在小文件列表中它没有显示出很大的区别
我认为父任务完成,子任务立即杀人。
有什么想法吗?
谢谢。
您的代码是我见过的代码量最大的代码之一。
这是使用 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);
});
就是这样。这一切都是使用后台线程处理的。它摆脱了所有这些 类,只做你需要的工作。
如果你想中途取消,就这样做:
subscription.Dispose();
如果您想知道它何时完成,只需执行以下操作:
var subscription = query.Subscribe(file =>
{
ParseFinish(file);
}, () =>
{
/* Handle the query is finished here */
});