Замените цикл While () на Timer, чтобы предотвратить зависание графического интерфейса [Многопоточность?] - PullRequest
1 голос
/ 19 января 2012

Как я могу использовать класс Timer и события таймера, чтобы превратить этот цикл в цикл, который выполняет чанки одновременно? Мой текущий метод только запуска цикла сохраняет зависание интерфейса вспышки / воздуха.

Я пытаюсь достичь многопоточности псевдо. Да, это от wavwriter.as:

// Write to file in chunks of converted data.
    while (dataInput.bytesAvailable > 0) 
    {
        tempData.clear();
        // Resampling logic variables
        var minSamples:int = Math.min(dataInput.bytesAvailable/4, 8192);
        var readSampleLength:int = minSamples;//Math.floor(minSamples/soundRate);
        var resampleFrequency:int = 100;  // Every X frames drop or add frames
        var resampleFrequencyCheck:int = (soundRate-Math.floor(soundRate))*resampleFrequency;
        var soundRateCeil:int = Math.ceil(soundRate);
        var soundRateFloor:int = Math.floor(soundRate);
        var jlen:int = 0;
        var channelCount:int = (numOfChannels-inputNumChannels);
        /*
        trace("resampleFrequency: " + resampleFrequency + " resampleFrequencyCheck: " + resampleFrequencyCheck
            + " soundRateCeil: " + soundRateCeil + " soundRateFloor: " + soundRateFloor);
        */
        var value:Number = 0;
        // Assumes data is in samples of float value
        for (var i:int = 0;i < readSampleLength;i+=4)
        {
            value = dataInput.readFloat();
            // Check for sanity of float value
            if (value > 1 || value < -1)
                throw new Error("Audio samples not in float format");

            // Special case with 8bit WAV files
            if (sampleBitRate == 8)
                value = (bitResolution * value) + bitResolution;
            else
                value = bitResolution * value;

            // Resampling Logic for non-integer sampling rate conversions
            jlen = (resampleFrequencyCheck > 0 && i % resampleFrequency < resampleFrequencyCheck) ? soundRateCeil : soundRateFloor; 
            for (var j:int = 0; j < jlen; j++)
            {
                writeCorrectBits(tempData, value, channelCount);
            }
        }
        dataOutput.writeBytes(tempData);
    }
}

1 Ответ

0 голосов
/ 24 января 2012

Я однажды реализовал псевдо-многопоточность в AS3 путем разбиения задачи на куски вместо разделения данных на куски.

Мое решение может быть неоптимальным, но оно работало хорошо дляя в контексте выполнения большого поиска в глубину, в то же время позволяя флэш-игре хорошо воспроизводиться.

  • Используйте переменную ticks для подсчета "тиков" вычислений, аналогично CPUтактыКаждый раз, когда вы выполняете какую-либо операцию, вы увеличиваете этот счетчик на 1. Увеличивайте его еще больше после выполнения более тяжелой операции.
  • В определенных частях вашего кода вставляйте контрольные точки, где вы проверяете, если ticks > threshold , где threshold - это параметр, который вы хотите настроить после того, как эта псевдо-многопоточность работает.
  • Если отметка> порог на контрольной точке, вы сохраняететекущее состояние вашей задачи, установите тики на ноль, затем выйдите из функции.
  • Метод должен быть повторен позже, поэтому здесь вы используете таймер с параметром interval , который также должен бытьнастроен позже.
  • При перезапуске метода используйте сохраненное состояние приостановленной задачи, чтобы определить, где ваша задача должна быть возобновлена.

Для вашей конкретной ситуации я бы предложил разбитьзадачи циклов для , вместо того, чтобы думать о цикле while.Идея состоит в том, чтобы прервать циклы for, запомнить их состояние, а затем продолжить после интервала покоя.

Для упрощения представьте, что у нас есть только самый лучший цикл for.Эскиз нового метода:

WhileLoop: while (dataInput.bytesAvailable > 0 && ticks < threshold) 
{
  if(!didSubTaskA) {
    // do subtask A...
    ticks += 2;
    didSubTaskA = true;
  }

  if(ticks > threshold) {
    ticks = 0;
    restTimer.reset();
    restTimer.start(); // This dispatches an event that should trigger this method
    break WhileLoop;
  }

  for (var i:int = next_unused_i;i < readSampleLength;i+=4) {
    next_unused_i = i+1;
    // do subtask B...
    ticks += 1;
    if(ticks > threshold) {
      ticks = 0;
      restTimer.reset();
      restTimer.start();
      break WhileLoop;
    }
  }

  next_unused_i = 0;
  didSubTaskA = false;
}
if(ticks > threshold) {
  ticks = 0;
  restTimer.reset();
  restTimer.start();
}

Переменные Тики , Порог , restTimer , next_unused_i и didSubTaskA важны и не могут быть локальными переменными метода.Они могут быть статическими или переменными класса.Подзадача A - это та часть, где вы «пересчитываете логические переменные», а также используемые там переменные не могут быть локальными переменными, поэтому сделайте их также переменными класса, чтобы их значения могли сохраняться при выходе из системы и возвращении к методу.

Вы можете сделать его более приятным, создав собственный класс Task и сохранив там все состояние прерванного алгоритма.Кроме того, вы можете сделать контрольную точку локальной функцией.

Я не тестировал приведенный выше код, поэтому не могу гарантировать, что он работает, но идея в основном такова.Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...