2

我有一个包含一堆部分的应用程序,每个部分都包含需要大量时间来计算的数据。我可以看到一些方法:

  1. 简单的解决方案1:计算应用程序启动时所有部分的数据。这意味着应用程序启动会很慢。

  2. 简单的解决方案 2:在用户加载时计算每个部分中的数据。这意味着加载每个部分会很慢(这很糟糕,因为每个部分都必须进行大量的渲染计算,所以它们已经有点慢了。

  3. 由于性能对于此应用程序至关重要,因此这些解决方案都不是理想的。所以这给我带来了一个不太简单的解决方案:在应用程序启动时,开始在后台线程上计算部分数据。这个解决方案的问题是我没有很好的方法来预测用户将首先加载哪个部分。因此,如果他们加载最后一部分以加载到后台线程上,他们最终会等待比我刚刚使用解决方案 2 时更长的时间。

  4. 所以这给我带来了解决方案:在应用程序启动时,开始在后台线程上计算部分数据,但是当用户加载部分时,暂停后台线程并开始计算用户请求的部分。除非计算已经开始,在这种情况下你让它完成。

我不确定如何实现解决方案 4。我认为最简单的解决方案可能是使用优先级队列并在加载任务时提高其优先级,但我不确定如何在 C# 中实现这一点。这是一个合理的方法吗?C# 中的优先级队列有哪些好的库?

4

2 回答 2

1

作为解决方案 4 的修改,您可以开始在后台加载每个部分。当用户选择一个部分时,检查它当前是否正在由主线程队列加载,如果没有,则分拆一个新线程并以更高的优先级加载该部分。当然,您会希望从主任务队列中删除此选择。

这是从 MSDN 设置优先级的示例

于 2012-11-30T19:36:12.973 回答
1

因此,我们将从对象的数组(或其他一些数据结构,如果需要)开始Task<Section>

private Task<Section>[] sections = new Task<Section>[5];

您应该确保在应用程序的最开始(而不是在后台)创建集合并实际定义任务。

for (int i = 0; i < sections.Length; i++)
{
    int sectionNumber = i; //copy for closure
    Task<Section> next = new Task<Section>(() => CreateSection(sectionNumber));
    //note the task isn't started.
    sections[i] = next;
}

然后你可以启动后台任务来实际处理一个任务:

Task.Run(() =>
{
    for (int i = 0; i < sections.Length; i++)
    {
        EnsureStarted(sections[i]);
        sections[i].Wait();
    }
});

Parallel.For如果您想让多个线程处理项目,您可以使用。

该方法使用此辅助方法:

public void EnsureStarted(Task task)
{
    if (task.Status == TaskStatus.Created)
    {
        task.Start();
    }
}

然后真正得到一个完成的部分(如果需要,开始它):

public Section GetFinishedSection(int sectionNumber)
{
    EnsureStarted(sections[sectionNumber]);
    return sections[sectionNumber].Result;
}

如果您需要它的非阻塞版本(可能是await它),您可以使用它:

public Task<Section> EnsureSectionComplete(int sectionNumber)
{
    EnsureStarted(sections[sectionNumber]);
    return sections[sectionNumber];
}
于 2012-11-30T20:10:48.410 回答