【问题标题】:Java: optimization of method ran every 10 microsecondsJava:每 10 微秒运行一次方法的优化
【发布时间】:2016-04-16 19:18:58
【问题描述】:

编辑:我用nanoTime() 做了一些println()ing,发现stepPins[pin].toggle() 需要4226 微秒。现在我需要找到一种更快的切换引脚的方法。

我正在编写一个程序来控制音乐软盘驱动器阵列。目前,我有一个方法每 10 微秒运行一次,并通过读取 01001011 形式的短片来标记必要的软盘,其中 1=tick floppy(有 8 张软盘)。

由于某种原因,代码运行速度太慢,导致音符频率偏离。

这里是方法和它的类:

public class Timer implements Runnable
{
    @Override
    public void run()
    {
        int i = Main.currentSteps.get(Main.time);
        try
        {
            if (Main.time > Main.maxTime)
            {
                Main.executor.remove(Main.timer);
                FloppyController.resetAll();
            }
            if ((i & 1) == 1)
            {
                FloppyController.stepPin(0);
            }
            if ((i & 2) == 2)
            {
                FloppyController.stepPin(1);
            }
            if ((i & 4) == 4)
            {
                FloppyController.stepPin(2);
            }
            if ((i & 8) == 8)
            {
                FloppyController.stepPin(3);
            }
            if ((i & 16) == 16)
            {
                FloppyController.stepPin(4);
            }
            if ((i & 32) == 32)
            {
                FloppyController.stepPin(5);
            }
            if ((i & 64) == 64)
            {
                FloppyController.stepPin(6);
            }
            if ((i & 128) == 128)
            {
                FloppyController.stepPin(7);
            }
        }
        catch (Exception e) {}
        Main.time++;
    }
}

以及它的价值,我的Main.java 课程的相关部分:

public class Main
{
    public static ArrayList<Short> currentSteps;
    public static ArrayList<Note> all = new ArrayList<Note>();
    public static long maxTime = 0;
    public static ScheduledThreadPoolExecutor executor;
    public static Timer timer;

    public static int time;

    public static void main(String[] args) throws InterruptedException, InvalidMidiDataException, IOException, MidiUnavailableException
    {
        //initialize
        FloppyController.init();
        currentSteps = new ArrayList<Short>();
        FloppyController.resetAll();

        for (int o = 0; o < Math.ceil(maxTime / 10); o++)
        {
            currentSteps.add((short) 0);
        }

        //populate list
        for (Note n : all)
        {
            for (int a = Math.round(n.timeStart / 10); a <= Math.round(n.timeEnd / 10); a += n.wait)
            {
                currentSteps.set(a, (short) (currentSteps.get(a) + (((currentSteps.get(a) & (short) Math.pow(2, n.channel)) == Math.pow(2, n.channel)) ? 0 : Math.pow(2, n.channel))));
            }
        }

        //start play executions
        executor = new ScheduledThreadPoolExecutor(1);
        long resolution = 10; //# of microsecond iterations
        timer = new Timer();
        executor.scheduleAtFixedRate(timer, 0, resolution, TimeUnit.MICROSECONDS);
    }

如何优化Timer.classrun()方法?

我也在考虑将 currentSteps ArrayList 更改为 HashMap,并且只包含非零值及其相应时间作为键,因为我在运行它的 Raspberry Pi 上遇到内存问题。

这里是stepPin 方法:

public static void stepPin(int pin) throws InterruptedException
    {
        if (pinPositions[pin] >= 79)
        {
            changeDirection(pin, true);
        }
        else if(pinPositions[pin] < 0)
        {
            changeDirection(pin, false);
        }
        stepPins[pin].toggle();
        stepPins[pin].toggle();
        pinPositions[pin] += pinDirections[pin].isLow() ? 1 : -1;
    }

【问题讨论】:

  • stepPin 是否会阻塞(直到软盘发出声音)?
  • 将方法添加到主要问题,可能是一个好主意来安排而不是运行stepPin()
  • 定时器不准确,它会尽力每x ms运行一次,但这取决于底层系统。
  • @TT。有更好的选择吗?至少它比 Thread.sleep 好:P
  • 请注意 println() 也有开销,Java 中的控制台 IO 传统上很慢。我建议改为写入缓冲文件。

标签: java optimization timer raspberry-pi


【解决方案1】:

我建议每个软盘驱动器启动 1 个线程,并使用两个字节数组作为缓冲区(我们称它们为“A”和“B”)来安排声音。缓冲区应该足够大,可以播放几秒钟的音乐。伪代码如下:

  • 初始化:用音乐的前几秒填充 A 缓冲区。启动从 A 缓冲区读取的所有软盘线程。
  • 主线程:用下一秒的音乐填充所有 B 缓冲区。等到软盘线程到达 B 缓冲区(按经过的时间)。然后写入 A 缓冲区,依此类推,直到乐谱用完。
  • 软盘线程:读取当前缓冲区,或者使用忙等待(高清晰度,高 CPU 使用率)或使用“精确”版本的 sleep(取决于操作系统的定义,低 CPU 使用率)。通过 System.nanoTime() 与他人保持同步。当 A 缓冲区耗尽时,切换到 B 缓冲区。

假设 stepPin 正在阻塞,但仅阻塞其线程,这将使您的线程与这些延迟隔离。

【讨论】:

  • 我可以做多个线程吗?请记住,我使用的是 Raspberry Pi。只有1个核心。如果我运行多个 Java 进程,它甚至会产生影响吗?
  • 您当然可以启动多个线程 - 如果问题是阻塞 IO,如果 time-to-context-switch
猜你喜欢
  • 2018-11-08
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 2015-01-18
  • 2012-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多