Полный цикл асинхронизации Bluebird [дубликат]

Примечание. Ниже применимо к Python 3.3+, поскольку оно использует yield_from . six также является сторонним пакетом, хотя он стабилен. В качестве альтернативы вы можете использовать sys.version.


В случае obj = [[1, 2,], [3, 4], [5, 6]] все решения здесь хороши, включая понимание списка и itertools.chain.from_iterable.

Однако рассмотрим этот несколько более сложный случай:

>>> obj = [[1, 2, 3], [4, 5], 6, 'abc', [7], [8, [9, 10]]]

Здесь есть несколько проблем:

  • Один элемент 6 - это просто скаляр; это не будет истребимым, поэтому приведенные выше маршруты не сработают здесь.
  • Один элемент 'abc', является технически итерируемым (все str s). Тем не менее, чтение между строками немного, вы не хотите рассматривать его как таковое - вы хотите рассматривать его как один элемент.
  • Последний элемент [8, [9, 10]] сам является вложенным итерабельным , Исходное понимание списка и chain.from_iterable извлекают только «1 уровень вниз».

Вы можете исправить это следующим образом:

>>> from collections import Iterable
>>> from six import string_types

>>> def flatten(obj):
...     for i in obj:
...         if isinstance(i, Iterable) and not isinstance(i, string_types):
...             yield from flatten(i)
...         else:
...             yield i


>>> list(flatten(obj))
[1, 2, 3, 4, 5, 6, 'abc', 7, 8, 9, 10]

Здесь вы проверяете, -элемент (1) повторяется с помощью Iterable , ABC из itertools, но также должен гарантировать, что (2) элемент не "string-like . "

47
задан georgephillips 27 April 2012 в 04:53
поделиться

3 ответа

У вас есть выбор с или без webWorkers:

Без WebWorkers

Для кода, который должен взаимодействовать с DOM или с большим количеством других состояний в вашем приложении, вы можете 't использовать webWorker, поэтому обычное решение состоит в том, чтобы разбить вашу работу на куски, каждый кусок работы на таймере. Разрыв между кусками с таймером позволяет движку браузера обрабатывать другие события, которые происходят, и не только позволит пользователю вводить обработку, но также позволяет рисовать экран.

Обычно вы можете позволить себе обрабатывать более одного на каждом таймере, который является более эффективным и быстрым, чем только один за каждый таймер. Этот код дает потоку пользовательского интерфейса возможность обрабатывать любые ожидающие события пользовательского интерфейса между каждым блоком, который будет поддерживать активный пользовательский интерфейс.

function processLargeArray(array) {
    // set this to whatever number of items you can process at once
    var chunk = 100;
    var index = 0;
    function doChunk() {
        var cnt = chunk;
        while (cnt-- && index < array.length) {
            // process array[index] here
            ++index;
        }
        if (index < array.length) {
            // set Timeout for async iteration
            setTimeout(doChunk, 1);
        }
    }    
    doChunk();    
}

processLargeArray(veryLargeArray);

Вот рабочий пример концепции - не эта же функция, но другая который использует ту же идею setTimeout() для тестирования вероятностного сценария с большим количеством итераций: http://jsfiddle.net/jfriend00/9hCVq/


Вы можете сделать вышеприведенную версию более общей версии, которая вызывает функцию обратного вызова, например .forEach(), например:

// last two args are optional
function processLargeArrayAsync(array, fn, chunk, context) {
    context = context || window;
    chunk = chunk || 100;
    var index = 0;
    function doChunk() {
        var cnt = chunk;
        while (cnt-- && index < array.length) {
            // callback called with args (value, index, array)
            fn.call(context, array[index], index, array);
            ++index;
        }
        if (index < array.length) {
            // set Timeout for async iteration
            setTimeout(doChunk, 1);
        }
    }    
    doChunk();    
}

processLargeArrayAsync(veryLargeArray, myCallback, 100);

Вместо того, чтобы угадывать, сколько штук сразу, это также возможно, чтобы прошедшее время было ориентиром для каждого фрагмента и позволяло ему обрабатывать столько, сколько может за определенный промежуток времени. Это несколько автоматически гарантирует отзывчивость браузера, независимо от того, насколько интенсивна итерация процессора. Таким образом, вместо того, чтобы передавать размер фрагмента, вы можете передать значение в миллисекундах (или просто использовать интеллектуальное значение по умолчанию):

// last two args are optional
function processLargeArrayAsync(array, fn, maxTimePerChunk, context) {
    context = context || window;
    maxTimePerChunk = maxTimePerChunk || 200;
    var index = 0;

    function now() {
        return new Date().getTime();
    }

    function doChunk() {
        var startTime = now();
        while (index < array.length && (now() - startTime) <= maxTimePerChunk) {
            // callback called with args (value, index, array)
            fn.call(context, array[index], index, array);
            ++index;
        }
        if (index < array.length) {
            // set Timeout for async iteration
            setTimeout(doChunk, 1);
        }
    }    
    doChunk();    
}

processLargeArrayAsync(veryLargeArray, myCallback);

С WebWorkers

Если код в вашем петле не требуется доступ к DOM, тогда можно поместить весь временной код в webWorker. WebWorker будет запускаться независимо от главного браузера Javascript, а затем, когда он будет выполнен, он сможет передавать любые результаты с помощью postMessage.

WebWorker требует отделить весь код, который будет запущен в webWorker, в отдельный скрипт файл, но он может завершиться без каких-либо проблем с блокировкой обработки других событий в браузере и без беспокойства по поводу приглашения «не отвечающего сценария», который может возникнуть при выполнении долгого процесса в основном потоке.

70
ответ дан jfriend00 31 August 2018 в 10:04
поделиться

Основываясь на @ jfriend00, вот прототип версии:

if (Array.prototype.forEachAsync == null) {
    Array.prototype.forEachAsync = function forEachAsync(fn, thisArg, maxTimePerChunk, callback) {
        let that = this;
        let args = Array.from(arguments);

        let lastArg = args.pop();

        if (lastArg instanceof Function) {
            callback = lastArg;
            lastArg = args.pop();
        } else {
            callback = function() {};
        }
        if (Number(lastArg) === lastArg) {
            maxTimePerChunk = lastArg;
            lastArg = args.pop();
        } else {
            maxTimePerChunk = 200;
        }
        if (args.length === 1) {
            thisArg = lastArg;
        } else {
            thisArg = that
        }

        let index = 0;

        function now() {
            return new Date().getTime();
        }

        function doChunk() {
            let startTime = now();
            while (index < that.length && (now() - startTime) <= maxTimePerChunk) {
                // callback called with args (value, index, array)
                fn.call(thisArg, that[index], index, that);
                ++index;
            }
            if (index < that.length) {
                // set Timeout for async iteration
                setTimeout(doChunk, 1);
            } else {
                callback();
            }
        }

        doChunk();
    }
}
0
ответ дан cjbarth 31 August 2018 в 10:04
поделиться

Ниже приведена демонстрация этого цикла «async». это «задерживает» итерацию в течение 1 мс и в течение этой задержки, это дает UI шанс что-то сделать.

function asyncLoop(arr, callback) {
    (function loop(i) {

        //do stuff here

        if (i < arr.Length) {                      //the condition
            setTimeout(function() {loop(++i)}, 1); //rerun when condition is true
        } else { 
            callback();                            //callback when the loop ends
        }
    }(0));                                         //start with 0
}

asyncLoop(yourArray, function() {
    //do after loop  
})​;

//anything down here runs while the loop runs

Существуют альтернативы, например веб-работники и в настоящее время предлагается setImmediate , который afaik, на IE , с префиксом.

5
ответ дан Joseph 31 August 2018 в 10:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: