延迟执行的最佳方法

时间:2015-11-30 06:32:51

标签: c# wpf multithreading task-parallel-library

假设我有一个方法,我通过Task.Factory.StartNew()在一个单独的线程中运行 此方法报告了很多进度(IProgress),它冻结了我的GUI。 我知道简单地减少报告数量就是一个解决方案,比如仅报告十分之一,但在我的情况下,我真的想要获取所有报告并在我的GUI中显示它们。

我的第一个想法是将所有报告排队并逐一处理,暂停每一报告。

首先:这是一个不错的选择吗?

其次:如何实现?使用计时器或使用某种Task.Delay()

更新
我会试着更好地解释一下。发送到GUI的进度包括我在地图上显示的地理坐标。一个接一个地显示每个进度在地图上提供某种动画。这就是为什么我不想跳过它们中的任何一个。

实际上,我不介意我在另一个线程中执行的方法是否在动画之前完成。我想要的是确保所有点都显示至少一段时间(比方说200毫秒)。

2 个答案:

答案 0 :(得分:2)

如果这是结果,那么在单独的线程中运行进程的整个过程就会被浪费。因此,我的第一个建议是尽可能减少更新次数。

如果这是不可能的,也许你可以修改你发送的数据作为每次更新的一部分。用于报告的对象或数据结构有多大,有多复杂?可以通过降低其复杂性来提高性能吗?

最后,您可以尝试另一种方法:如果您创建仅处理报告的第三个​​线程,并以更大的块将其传递到GUI,该怎么办?如果你让你的工作线程向这个记者线程报告它的状态,那么让记者线程仅偶尔向你的主GUI线程报告(例如,每10个中,你自己在上面建议,然后报告10个块数据一次),那么你不会经常调用你的GUI,但你仍然可以保留处理中的所有状态数据,并使其在GUI中可用。

我不知道这对你的特殊情况有多可行,但它可能值得一两个实验?

答案 1 :(得分:1)

我对您的解决方案有很多疑虑,但我无法确定哪一个在没有代码示例的情况下可能会出现问题。

首先,Stephen Cleary在他的StartNew is Dangerous文章中指出了使用默认参数的方法存在的真正问题:

  

对于简单的案例来说足够简单,但让我们考虑一个更现实的例子:

private void Form1_Load(object sender, EventArgs e)
{
    Compute(3);
}

private void Compute(int counter)
{
    // If we're done computing, just return.
    if (counter == 0)
        return;

    var ui = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Factory.StartNew(() => A(counter))
        .ContinueWith(t =>
        {
            Text = t.Result.ToString(); // Update UI with results.

            // Continue working.
            Compute(counter - 1);
        }, ui);
}

private int A(int value)
{
    return value; // CPU-intensive work.
}
     

...   现在,问题返回:A运行什么线程?来吧,走过去吧;你应该在这一点上有足够的知识来找出答案   准备? 方法A第一次在线程池线程上运行,然后在最后两次在UI线程上运行。

我强烈建议您阅读整篇文章,以便更好地理解StartNew方法用法,但是想要指出最后的建议:

  

不幸的是,StartNew唯一需要重载的重载   TaskScheduler还要求您指定CancellationToken和   TaskCreationOptions。这意味着要使用   Task.Factory.StartNew可靠,可预测地将工作排到了   线程池,你必须使用这样的重载:

Task.Factory.StartNew(A, CancellationToken.None,
  TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
     

真的,这有点荒谬。只需使用Task.Run(() => A());

因此,只需切换您正在创建新闻任务的方法,就可以轻松改进您的代码。但是对于你的问题还有其他一些建议:

  1. 使用BlockingCollection来存储报告,并将一个简单的消费者从此队列写入UI,因此您总是需要有限数量的报告来表示,但最后所有报告都将被处理。
  2. 使用ConcurrentExclusiveSchedulerPair class作为您的逻辑:要生成报告,请使用ConcurrentScheduler Property并使用ExclusiveScheduler Property显示报告。