【问题标题】:Android - Is it possible to run a thread update at least once per millisecond?Android - 是否可以每毫秒至少运行一次线程更新?
【发布时间】:2013-10-15 14:22:56
【问题描述】:

我想编写一个需要在指定时间执行某些操作的 Android 应用程序(确切地说是游戏)。这些更新的精度应不低于 1ms。这可能吗?

我尝试运行一个线程并使用 System.nanoTime() 测量更新之间的时间。结果,有数百次更新之间的时间等于或长于 1 毫秒。

我能否以某种方式达到一种精度,确保每 1 毫秒至少执行一个循环?

这是我用于测试的代码:

public class MyThread extends Thread
{
    private boolean running = false;
    public void setRunning(boolean running)
    {
        this.running = running;
    }

    public MyThread()
    {
        this.setPriority(MAX_PRIORITY);
    }

    @Override
    public void run()
    {
        long currentTimeNano = 0;
        long lastFrameTimeNano = 0;
        long nanoFrameDelay = 0;
        int longDelays = 0; //Number of delays >= 1ms

        while(running)
        {
            currentTimeNano = System.nanoTime();

            //Measure delay between updates in ns
            nanoFrameDelay = currentTimeNano - lastFrameTimeNano;

            if(nanoFrameDelay >= 1000000)
                longDelays++;

            lastFrameTimeNano = currentTimeNano;
        }
    }
}

提前谢谢你!

【问题讨论】:

  • 需要这么多更新是很不寻常的。能否提供更多背景信息?
  • 为什么需要至少每毫秒更新一次?这意味着帧率超过 1000 FPS,大多数游戏都在 30-120 范围内。
  • 我想将应用程序的行为与音乐同步。例如,我想在音乐的当前播放时间等于 571ms,然后是 823ms,然后是 6531ms 等时做一些事情。
  • 这不是 FPS。我不想每毫秒渲染一帧,我只想执行所需的计算。
  • 用户如何看待你做“当音乐的当前播放时间等于 571ms”而不是 570ms 或 572ms 之间的区别?另外,请说明您希望在这些时间点具体做什么。

标签: java android multithreading performance precision


【解决方案1】:
class SampleTask extends TimerTask {
    public void run() {
       System.out.println("Hello World!"); 
    }
 }


 Timer timer = new Timer();
 timer.schedule(new SampleTask(), 1);

【讨论】:

    【解决方案2】:

    使用常规的 java、硬件和 Thread.sleep() 之类的东西无法达到 1ms 的精度。

    要达到 1 毫秒的精度,您需要一个实时平台。

    取自http://www.onjava.com/pub/a/onjava/2006/05/10/real-time-java-introduction.html

    据 Sun 杰出工程师 Greg Bollella 所说 Microsystems 和实时 Java 的作者之一 规范,实时意味着“能够可靠地和 可预测地推理和控制程序的时间行为 逻辑。”实时并不意味着“快”,正如许多开发人员所可能的那样 思考;当对现实世界的反应时,它意味着可预测和可靠 事件是必需的。实时计算机将始终响应之前 您为其分配的特定截止日期。取决于你如何 设定你的最后期限,许多系统都可以被称为实时。

    查看此讨论: Java - alternative to thread.sleep

    更具体地说,本文讨论了如何部署实时应用程序: http://www.embedded.com/electronics-blogs/cole-bin/4372870/Real-time-Android--real-possibility--really-really-hard-to-do---or-just-plain-impossible--

    或者这个:http://www.ittc.ku.edu/~niehaus/classes/753-f10/notes/sarvesh_android.pdf

    基本上,我认为您对股票市场应用程序不走运。如果这是为您的公司准备的,您可以尝试使每个设备都生根并使用实时内核,但您正在冒险进入大部分未知领域。即使使用该路线,也无法保证 1 毫秒的准确度。

    但是....


    编辑:看来您的案例不需要 1 毫秒的精度。碰巧我的论文是基于视听线索和对同时性的感知。

    长话短说,对于 2 个音频信号(1 个来自左耳,1 个来自右耳),只有当两个信号间隔超过 10 毫秒时,才能判断两个脉冲输入是否有延迟。大多数人在区分 50 毫秒时的事件顺序时遇到了问题。

    对于视力而言,正常人的眼睛只能在大约 150Hz 下工作,因此任何小于 7ms 的延迟都没有什么区别。我见过的最佳刷新率大约是 200Hz,或 5ms 延迟。但是,这仅用于检测明亮的闪光,而不是您确定 2 个事件并发的情况。对于类似于您正在尝试做的事情,我能够安全地获得长达 60 毫秒的延迟,而不会在视听同时性方面出现任何明显的不匹配。您的用例可能需要更少的东西。 ~50ms 似乎是一个神奇的数字。对于这种类型的准确性, sleep() 应该绰绰有余。您的案例不需要实时系统。

    【讨论】:

    • 哇,对于这样的游戏,60ms 绝对不够!多年来我一直在玩这类游戏,它们测量玩家的准确度甚至可以精确到大约 16 毫秒。
    • 显然您希望它尽可能小,而且我记得在某处看到 Sleep() 为您提供了大约 15 毫秒的分辨率 - 虽然找不到源。我的帖子的重点是说 1ms 在 android 上是不可能的,正常的线程延迟应该足够了(绝对小于 50ms)。根据我的研究,虽然可能与您的游戏略有不同,但 60 毫秒是它变得明显的时间点。尽量将其保持在 50 毫秒以下,只是不要让自己因编程延迟而发疯。
    【解决方案3】:

    我将有一个预先计算的用户触摸屏幕的时间列表(以毫秒为单位),我想测量它与实际触摸时间之间的差异。

    这不需要“每毫秒至少运行一次线程更新”。您可以从MediaPlayer 中找出音乐的毫秒偏移量,并将其与您的预期值进行比较。您的预期值基于您启动整个过程的时间和触摸事件的当前时间。

    【讨论】:

    • 如果我做出这样的条件: if(mediaPlayer.getCurrentPosition() == desiredMillisecond) 它很少触发。例如,如果我的 desiredMillisecond 是 500,更新在 499 运行,下一个是 501,则跳过所需的时间,我被卡住了......
    • @GrzegorzBrose:如果您希望游戏玩家完全与您的时代相匹配,那么您要么是疯了,要么是计划让机器人玩您的游戏,或者两者兼而有之。您需要给用户一个时间窗口。 dberm22 建议 50ms,但您也可以尝试并得出一个合适的值。所以如果玩家的位置和期望的时间之间的差异小于你的窗口,你就说用户击中了标记。请记住,时间差可能为负数,因此请将绝对值与 25 毫秒进行比较,以允许响应稍快或稍慢。
    • 呃,不,我不希望玩家能够以 1 毫秒的精度玩游戏,我怀疑任何人都能够做到这一点,哈哈。当然我要实现一个定时窗口。虽然 50 毫秒太长了。例如“Dance Dance Revolution”的时间窗口定义为 16 毫秒。
    • 不是讽刺,我很想看看那个 16ms 数字的来源。在我对一个人打出稳定节拍的测试中,我录制的最好成绩来自一位专业音乐家,她的平均标准偏差约为 16 毫秒——多一些,少一些。普通人至少是这个数字的两倍。如果我没记错的话,大约是 50 毫秒,虽然它可能会更少——我记不清了……但绝对不是 16 毫秒。如果我是你,我会按照 CommonsWare 的建议去做,并自己研究以找到合适的时间。
    • 一点问题都没有!这是来源:stepmania.com/wiki/Stepmania.ini#Timing_Windows 这是完全有可能的证据:youtube.com/watch?v=nt0nFKpTH3I - 这家伙正在演奏“In the groove”,并以“Fantastic”(又名“Marvelous”)的准确度为音符评分 100%。从第一个链接您可以看到该游戏中“Marvelous”的计时窗口设置为 21.5 毫秒。我找不到有人在“Dance Dance Revolution Extreme”中获得 100% 的视频,该视频具有提到的 16 毫秒时间窗口,但相信我,这绝对是可能的 :)
    【解决方案4】:

    您的问题是如何以足够准确的时间 (1ms) 将用户输入与音频输出相关联,以使适当的工作。

    首先,我认为 1ms 是努力达到的正确精度。

    其次,这并不容易。 JAVA 不是实时的,Android 也不是。我认为您不妨忘记所有传统方法,因为硬件、操作系统和语言的延迟变化太大。

    第三,如果用户输入语音,您是否考虑过另一种格式?如果您的应用程序可以在播放音乐的同时进行录制,那么您将录制的(希望)是所有其他声音叠加在顶部的音乐。因此,您所要做的就是在录音和原件之间建立相关性,以衡量录音相对于原件的对齐方式,然后处理录音以获得可识别的用户声音。

    这样可以避免任何实时软件要求,并且您可以利用平台中唯一的半实时部分;声音输入和输出。信任平台实时播放和录制,以普通方式进行处理。

    您不会在用户输入后立即生成用户反应时间测量值,因此如果您需要在之后立即更新屏幕,则此技术可能不适合。但是,当您的测量完成时,它至少会是准确的。

    编辑

    用户的声音输入可能非常简单。例如,如果他们只是将手指放在麦克风上,那么录音会突然变得更安静。易于加工。或者,录音中不存在于原始录音中的任何音量增加都可以被视为用户输入,而无需实际识别额外的声音是什么。

    而且这不太可能与耳机一起使用......

    【讨论】:

    • 谢谢,但我需要立即向玩家展示准确性,而不是在游戏结束后。是的,它不适用于耳机......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 2017-04-20
    • 1970-01-01
    • 2019-05-06
    相关资源
    最近更新 更多