AsyncExecutor似乎不是异步的

时间:2017-01-21 23:43:33

标签: java multithreading libgdx

此问题已经过编辑,可以提供尽可能多的有关问题的信息,正如有人建议我应该做的那样。现在有了它的赏金 - 这似乎是正确的事情。祝你好运,人们!

不要忘记,如果您觉得我没有包含任何内容,您可以随时提出其他问题!

简介

我正在研究一个程序生成地形的系统,因为角色会使用各种不同的噪音走来走去 - 主要是perlin-simplex-noise。世界本身有三个维度,虽然它在游戏中被视为top-down in two dimensions

对于那些习惯于在程序上生成地形的人,您将意识到必须使用多线程才能在渲染器线程中不引起滞后尖峰。这正是我一直在尝试做的事情,在LibGDXAsyncExecutor以及相同的库AsyncTask的帮助下,这是一个在提供的线程上运行的任务由AsyncExecutor

问题

我的问题是AsyncExecutor似乎根本不是异步的。它会在我的渲染器线程中引起滞后尖峰,理论上它可以使用渲染器线程也使用的资源。然而,事情是,渲染器线程以新的“块”生成 - 我称之为区域 - AsyncExecutor然后处理。在AsyncExecutor完全生成之前,不允许呈现器线程呈现该资源。

RegionHandler

我有一个名为RegionHandler的班级,它将新区域放置在玩家移动的方向,并从相反的方向移除区域 - 以便程序不必知道超过13 x 9个区域一次。

以下是一段简短的代码,解释了它的工作原理 - 评论是否有简化讨论代码的不同部分

// These ‘if’s are triggered when the player moves
// to a certain position
if(addLeft)
{
    // Adds new regions to the left and removes to the right
    // ...

    // Submit ‘RegionLoader’ task to ‘asyncExecutor’
    // with regions that needs be generated as well as ‘toSends’ which is
    // also part of that generation
    asyncExecutor.submit(new RegionLoader(toGenRegions, toSends));      
}
else if(addRight)
{
    // Adds new regions to the right and removes to the left
    // ...

    // Same as previous ‘submit’ to the ‘asyncExecutor’
    asyncExecutor.submit(new RegionLoader(toGenRegions, toSends));
}

if(addBottom)
{
    // Adds new regions to the bottom and removes to the top
    // ...

    // Same as previous ‘submit’ to the ‘asyncExecutor’
    asyncExecutor.submit(new RegionLoader(toSend, toSends));
}
else if(addTop)
{
    // Adds new regions to the top and removes from the bottom
    // ...

    // Same as previous ‘submit’ to the ‘asyncExecutor’
    asyncExecutor.submit(new RegionLoader(toSend, toSends));
}

asyncExecutor实际上是AsyncExecutorRegionLoader实现了AsyncTask界面。我已经测试了这段代码需要多长时间才能完成 - 这段代码永远不会花费一毫秒的时间来运行。

Region在列表中处理:

List<List<Region>> regions;

RegionLoader

此类是一项能够由AsyncExecutor运行的任务。

private class RegionLoader implements AsyncTask<Object>
{
    private List<Region> regions;
    private List<ToSendInner> toSends;

    public RegionLoader(
            List<Region> regions, 
            List<ToSendInner> toSends)
    {
        this.regions = regions;
        this.toSends = toSends;
    }

    @Override
    public Object call() throws Exception
    {
        // Generates the ‘Region’s it has been given inside the constructor
        // ...

        return null;
    }
}

call()完成后,它会将boolean设置为true,以便呈现该特定Region

此外

虽然AsyncExecutor是异步的,但它会在渲染器线程内每隔一段时间引起一次滞后尖峰。如前所述,这可能是由AsyncExecutor使用与渲染器线程相同的资源引起的,但渲染器线程仅在允许的情况下呈现Region - 因此我无法看到为什么会导致滞后峰值。

到目前为止我尝试了什么

我尝试过使用常规Java线程,但I read somewhere由于支持Android开发的 LibGDX 而可能无法正常工作,Android在多线程方面没有相同的功能 - 但我真的错了!

此外

也许有人在他们的游戏开发职业中遇到过类似的问题?如果是这样,也许有人可以指出我正确的方向?

2 个答案:

答案 0 :(得分:1)

我将查看垃圾收集的效果,因为您似乎正在将新的Region对象传递给任务。请尝试重新使用/重新填充现有区域。

答案 1 :(得分:0)

我不记得有关Android和线程的任何问题并搜索但没有找到任何内容。你应该测试一下。

我将假设生成区域与openGL无关。所以你不必在主线程上运行它。

试试这个:主题+ Gdx.app.postRunnable()

new Thread(new Runnable() {
    Variables...
    public Runnable set(Variables... ) {
        // set variables
        return this;
    }
    @Override
    public void run() {
        // do stuff

        Gdx.app.postRunnable(() -> {
            // commit that stuff.

        });
    }
}.set(regions,whateverelse)).start();

如果你看一下AsyncExecutor的源代码,你会发现它完全一样。但只有它不会让第二个runnable同时运行。

https://github.com/libgdx/libgdx/blob/9b8f20b2d0e96e53f0f2b98dc8f6131c810aae71/gdx/src/com/badlogic/gdx/utils/async/AsyncExecutor.java

注意: AsyncExecutor的实现更改为在gwt后端立即执行。由于我猜的限制。你可能不应该以gwt为目标。

试试吧,让我知道。如果主线程仍然挂起,那是因为你在 //提交那些东西部分正在做什么。发布更多代码,还不足以理解问题的根源。

编辑:还可以使用Gdx.graphics.getDeltaTime()查看是否真的挂起。它可能是由其他东西引起的,所以要消除其他可能性,并找出真正的原因是否是这项任务。