【发布时间】:2021-04-06 07:39:48
【问题描述】:
我的软件中有一个后台任务应该无限期运行。
重复该任务(以及未来可能的其他任务)的代码如下所示:
public class RunTicketTasks
{
public async Task RunBackgroundTasks()
{
AssignTickets assignTickets = new AssignTickets();
while (true)
{
await assignTickets.AssignTicketCreator();
await Task.Delay(5 * 60 * 1000);
}
}
}
同时我有 WPF UI MainWindow.xaml,据我所知,这是应用程序入口点。
在public MainWindow 内我按如下方式启动任务:
public MainWindow()
{
InitializeComponent();
JiraBackgroundTasks.RunTicketTasks ticketTasks = new JiraBackgroundTasks.RunTicketTasks();
ticketTasks.RunBackgroundTasks();
}
显然,这会在同一个线程上启动任务(我相信)。任务已启动并成功运行,但由于长时间运行操作,UI 被阻塞。同时,当我取消注释最后一行 ticketTasks.RunBackgroundTasks(); 时,用户界面运行良好。
如何在后台启动任务以使我的用户界面仍然响应?
编辑:
我以这种方式开始任务的原因是因为异常处理。
我可以按照Task.Run(async () => await ticketTasks.RunBackgroundTasks()); 的建议在不同的线程上成功启动任务,但是如果出现问题,我不会收到任何异常。
如何在不阻塞 UI 的情况下启动任务并在引发异常时仍收到异常详细信息?
网上有如下说法:
await Task.Run(() => ticketTasks.RunBackgroundTasks());
但这不起作用,因为The await operator can only be used within an async method.
【问题讨论】:
-
第一个 sn-p 似乎没有任何异步。但如果是这样,您应该使用
await Task.Delay而不是Thread.Sleep。 但是 除此之外,我建议使用计时器甚至调度框架来代替重复任务。 -
好吧,您不是在这里创建(或从池中提取)单独的线程。作为第一步,您可能想查看
Task.Run。 -
同意@Fildor,您最好不要使用
Tasks 进行这种无限的后台处理,但您的解决方案是Task.Run(async () => await ticketTasks.RunBackgroundTasks());。 -
好的。还要注意:
RunBackgroundTasks方法返回的任务没有等待(它是一个即发即弃的任务),因此不会观察到可能的异常。如果您想在任务完成时收到通知,您应该await任务。或者,您可以将方法转换为async void而不是async Task,以便它具有事件处理程序语义(事件处理程序上未处理的异常会导致应用程序崩溃)。¨ -
不,
await不会阻塞 UI 线程。 Await 表示异步等待。简单来说,它为任务附加了一个延续,其中包含await关键字之后的所有代码。该代码将在任务完成时运行。阻塞 UI 线程的是Wait方法,正是由于这个原因,通常应该避免使用它。
标签: c# user-interface asynchronous task