使用后台并行无限循环 C# 读取缓冲区 [关闭]
Posted
技术标签:
【中文标题】使用后台并行无限循环 C# 读取缓冲区 [关闭]【英文标题】:Read a buffer with background parallel infinite loop C# [closed] 【发布时间】:2021-05-27 17:26:39 【问题描述】:我必须创建一个 WPF 应用程序 (.NET Framework) 来创建一个带有用户界面的程序。
当 GUI 工作时,程序必须继续,无限循环,在后台读取一个文件夹,该文件夹不断填充来自外部程序的新 txt 文件。
一个例子:
外部程序 --> 创建新的 txt 文件并将它们放入 名为“缓冲区”的文件夹 我的程序 --> 在后台启动一个无限循环,读取内容 每个文件并从“缓冲区”中删除它们此进程必须由主 GUI 控制,但不必停止其他进程。
我想我必须使用线程来并行化进程,但不幸的是我没有太多的 C# 经验,请你帮我提些建议好吗?
【问题讨论】:
忘记“无限循环”。您要么想通过例如 Timer 启动进程“运行”,要么使用 FileSystemWatcher( 注意:您可能迟早会发现您正在尝试处理仍在“传输中”的文件。您可能想从一开始就考虑这一点。 @GazTheDestroyer 我推荐IProgress
/ Progress
。
您可能感兴趣的另一件事是Dataflow。
@GazTheDestroyer 不,Task.Run 不会启动新线程,它将使用线程池中的线程。与 2010 年引入任务之前的 Dispatcher.BeginInvoke
kind-of-did 相同。不再需要使用 BeginInvoke
,绝对不是自 2012 年引入 await
以来
【参考方案1】:
我以前一直站在你的立场上。我不能分享实际的代码(当然),但这就是我所做的:
将“监视文件夹”至少分离到它自己的类中(如果不是子项目)。 将“处理文件”至少分离到它自己的类中。对于文件夹部分:
我使用FileSystemWatcher 来获取文件夹中存在新文件的通知。 EventHandler 所做的只是将文件路径放入ConcurrentDictionary<string,DateTime>
,将“最后一次看到”与路径一起存储为键。
每隔 5 秒(我认为是)运行的计时器过滤字典中所有超过 2.5 秒(半间隔)的条目。这是为了确保文件不再在传输中。不是真正的“100% 解决方案”,但效果很好。
选定的文件(路径字符串)被设置到“黑名单”中,以便在后续运行中被忽略,并发送到 Dataflow 管道。
然后处理:
一个。 data flow pipeline 完成了所有文件处理并最终发出完成的信号,因此可以将文件移动到“完成”文件夹并从黑名单中删除。
b.导致异常的文件与包含异常消息和堆栈跟踪的相应“filename.error”文件一起放入“需要手动交互”文件夹中,并从黑名单中删除。请注意,您可能需要处理重复的文件名。
唯一的区别是我必须在控制台应用程序中执行此操作,该应用程序在服务器上连续运行。后来我将它重构为一个真正的 Windows 服务。但是,您必须处理 WPF。不过,基本思想应该保持不变。您可能需要的只是一种显示流程并与之交互的正确方法。我强烈建议您关注MVVM pattern。
我还强烈建议采用其中一种漂亮的日志记录框架。
【讨论】:
【参考方案2】:如果您真的需要一个无限循环对文件进行一些后台工作,则不需要在现代 .NET 中显式使用线程。您可以使用 TPL 并启动一个后台任务,该任务在您的应用启动后运行无限循环。在无限循环中,您应该定期检查取消令牌以使后台任务能够正常完成。
我认为参考 TPL 文档是有道理的:https://docs.microsoft.com/en-US/dotnet/standard/parallel-programming/task-parallel-library-tpl
高级代码示例:
// Start your background task
void StartBackgroundWorker()
// _cts is a data members of some object that encapsulates the background activity
_cts = new CancellationTokenSource();
System.Threading.Tasks.Task.Run(() => TaskEntryPoint(cts.Token));
// Stop your background task
void StopBackgroundWorker()
_cts.Cancel();
_cts.Dispose();
// In the background task, check for cancellation
void TaskEntryPoint(CancellationToken token)
while (!token.IsCancellationRequested)
// complete a chunk of your background processing work
// and check whether cancellation was requested by the
// owner of the background worker
【讨论】:
不需要此代码。它也将任务视为线程。任务不是线程,它们没有入口点。在字段中存储任务是不好的做法。没有理由在任务中运行循环。所有这些代码都可以替换为while(!token.IsCancellationRequested) await Task.Run(()=>someHeavyWork);
不是我的反对意见,而是...您发布的是尝试使用任务重写 BackgroundWorker。 BGW 的问题不在于实现,而是整个概念
也不是反对者,而是don't useTask.Factory.StartNew
方法。请改用Task.Run
。也不要检查token.IsCancellationRequested
条件,因为它通常会导致不一致的取消行为。请改用ThrowIfCancellationRequested
。根据标准取消模式,兑现取消信号与取消操作抛出的OperationCanceledException
进行通信。以上是关于使用后台并行无限循环 C# 读取缓冲区 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
Qt 循环中加入QCoreApplication::processEvents退出后台运行