c# - 是否可以轮询任务是否完成?

标签 c# wpf task deadlock

我有一个长时间运行的任务,我不想阻塞 UI,所以我得到了一个 DispatcherTimer,我用它的 tick 事件来检查任务属性 IsCompleted 但这会导致某种死锁,因为我的应用程序停止响应

public partial class MainWindow : Window
{
    DateTime beginFirstPhase;
    DateTime beginSecondPhase;
    DispatcherTimer dispatcherTimer = new DispatcherTimer();
    IEnumerable<string> collection;
    Task firstPhaseTask;
    Task secondPhaseTask;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void button_Click(object sender, RoutedEventArgs e)
    {
        progressTxtBox.AppendText("Entering button click event handler\n");
        beginFirstPhase = DateTime.Now;

        dispatcherTimer.Tick += DispatcherTimer_Tick_FirstPhase;
        dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
        dispatcherTimer.Start();

        progressTxtBox.AppendText("Begining First Phase now\n");

        firstPhaseTask = Task.Factory.StartNew(() =>
            /*this is basically a big linq query over a huge collection of strings
            (58 thousand+ strings). the result of such query is stored in the field named
            collection, above*/), TaskCreationOptions.PreferFairness);
        progressTxtBox.AppendText("Awaiting First Phase completion...\n");
    }

    private void DispatcherTimer_Tick_FirstPhase(object sender, EventArgs e)
    {
        TimeSpan span = DateTime.Now - beginFirstPhase;
        //not even the line bellow is executed.
        statusTextBlock.Text = $"Running: {span.ToString()}";

        if (firstPhaseTask.IsCompleted)
        {
            dispatcherTimer.Stop();
            progressTxtBox.AppendText($"First Phase completed in {span.ToString()}\n");
            secondPhase();
        }
    }

    private void secondPhase()
    {
        beginSecondPhase = DateTime.Now;

        progressTxtBox.AppendText("Begining Second Phase now\n"));

        dispatcherTimer.Tick -= DispatcherTimer_Tick_FirstPhase;
        dispatcherTimer.Tick += DispatcherTimer_Tick_SecondPhase;
        dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
        dispatcherTimer.Start();

        int counter = 0;
        secondPhaseTask = Task.Factory.StartNew(() =>
        {
            foreach (string str in collection)
            {
                Dispatcher.Invoke(() => progressTxtBox.AppendText($"iteration <{counter++}>\n"));
                IEnumerable<Tuple<string, string> queryResult; // = another linq query
                foreach (var tuple in queryResult)
                {
                    Dispatcher.Invoke(() => outputListView.Items.Add($"{tuple.Item1} {tuple.Item2} {str}"));
                }
            }
        }, TaskCreationOptions.PreferFairness);
    }

    private void DispatcherTimer_Tick_SecondPhase(object sender, EventArgs e)
    {
        TimeSpan span = DateTime.Now - beginSecondPhase;
        statusTextBlock.Text = $"Running: {span.ToString()}";
        if (secondPhaseTask.IsCompleted)
        {
            dispatcherTimer.Stop();
            progressTxtBox.AppendText($"Second Phase completed in {span.ToString()}\n");
            progressTxtBox.AppendText("Execution Complete");
        }
    }
}

是什么导致了阻塞? Task.IsCompleted 会阻塞调用者的线程吗? 根本不可能像这样轮询任务吗?如果没有,还有其他选择吗?

最佳答案

您想通过使用 await 运算符“关闭”Task.Run。这样你就可以告诉用户“等待......”然后当任务完成时你会自动进入 Gui 线程。如果你想要进度报告,我认为这是通过 Progress 类完成的,但不记得了。无论如何,这应该让你接近......

private async void button_Click(object sender, RoutedEventArgs e)
{
    progressTxtBox.AppendText("Entering button click event handler\n");
    beginFirstPhase = DateTime.Now;

    dispatcherTimer.Tick += DispatcherTimer_Tick_FirstPhase;
    dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
    dispatcherTimer.Start();

    progressTxtBox.AppendText("Begining First Phase now\n");
   progressTxtBox.AppendText("Awaiting First Phase completion...\n");
    firstPhaseTask =await  Task.Factory.StartNew(() =>
        /*this is basically a big linq query over a huge collection of strings
        (58 thousand+ strings). the result of such query is stored in the field named
        collection, above*/), TaskCreationOptions.PreferFairness);
    progressTxtBox.AppendText("First Phase complete...\n");

}

我还建议将结果更改为...

 var results =await  Task<IEnumerable<OfType>>.Factory.StartNew(() =>{
          return context.where(p=>p.field = fieldvalue);

关于c# - 是否可以轮询任务是否完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37713488/

相关文章:

javascript - 服务器端数据表分页无法正常工作

wpf - 双击列表框项目以打开浏览器

algorithm - 根据技能向 worker 公平分配任务的算法

project-management - 有没有适合开发人员的不错的任务/待办事项应用/系统?

c# - 将对象转换为方法泛型类型

c# - #在网络发布期间定义符号

c# - 如何生成 24 小时后过期的唯一 token ?

c# - 在不更改 ControlTemplate 的情况下访问 TemplatePart?

c# - WPF图像源来自常量

android - 需要新任务后台中的单个 Activity