【问题标题】:background task is blocking main thread in wpf .net core application后台任务正在阻塞 wpf .net 核心应用程序中的主线程
【发布时间】: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


【解决方案1】:

一种方法是将任务包装在异步事件回调中:


public partial class MainWindow : Window
{
    // I mocked your missing types, replace with your own 
    class AssignTickets
    {
        public Task AssignTicketCreator() => Task.CompletedTask;
    }

    public class RunTicketTasks
    {
        public async Task RunBackgroundTasks()
        {
            AssignTickets assignTickets = new AssignTickets();
            int x = 0;
            while (true)
            {
                await assignTickets.AssignTicketCreator();
                await Task.Delay(1000);

                var isRunningOnDispatcher = Application.Current.Dispatcher ==
                    System.Windows.Threading.Dispatcher.FromThread(Thread.CurrentThread);
                Trace.WriteLine($"One second passed, running on dispatcher: {isRunningOnDispatcher}");

                // exception will also get thrown on the main thread
                if (x++ > 3) throw new Exception("Hello!");
            }
        }
    }

    public MainWindow()
    {
        InitializeComponent();

        // event fires on UI thread!
        this.Loaded += async (sender, args) =>
        {
            try
            {
                await new RunTicketTasks().RunBackgroundTasks();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        };
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 2013-07-09
    相关资源
    最近更新 更多