混合预先计算与延迟加载

时间:2012-11-30 19:21:55

标签: c# lazy-loading priority-queue preload

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

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

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

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

  4. 所以这让我得到解决方案:在应用启动时,开始计算后台线程上的部分数据,但是当用户加载部分时,暂停后台线程并开始计算用户请求的部分。 除非计算已经开始,否则你可以让它完成。

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

2 个答案:

答案 0 :(得分:1)

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

以下是来自MSDN的example设置优先级。

答案 1 :(得分: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];
}