Страницы

Поиск по вопросам

пятница, 24 мая 2019 г.

Потребление памяти PHP-генераторами

В документации говорится:
Генератор позволяет Вам писать код, использующий foreach для перебора набора данных без необходимости создания массива в памяти, что может привести к превышению вами лимита памяти, либо потребует довольно много времени для его создания. Вместо этого, Вы можете написать функцию-генератор, которая, по сути, является обычной функцией, за исключением того, что вместо возвращения единственного значения, генератор может yield столько раз, сколько необходимо для генерации значений, позволяющих перебрать исходный набор данных. Наглядным примером вышесказанного может послужить использование функции range() как генератора. Стандартная функция range() должна генерировать массив, состоящий из значений, и возвращать его, что может послужить результатом генерации огромных массивов: например, вызов range(0, 1000000), приведёт к использованию более чем 100 МБ памяти. В качестве альтернативы мы можем создать генератор xrange(), который использует память только для создания объекта Iterator и сохранения текущего состояния, что потребует не больше 1 килобайта памяти.

A generator allows you to write code that uses foreach to iterate over a set of data without needing to build an array in memory, which may cause you to exceed a memory limit, or require a considerable amount of processing time to generate. Instead, you can write a generator function, which is the same as a normal function, except that instead of returning once, a generator can yield as many times as it needs to in order to provide the values to be iterated over. A simple example of this is to reimplement the range() function as a generator. The standard range() function has to generate an array with every value in it and return it, which can result in large arrays: for example, calling range(0, 1000000) will result in well over 100 MB of memory being used. As an alternative, we can implement an xrange() generator, which will only ever need enough memory to create an Iterator object and track the current state of the generator internally, which turns out to be less than 1 kilobyte.

И приводится пример:
function xrange($start, $limit, $step = 1) { if ($start < $limit) { if ($step <= 0) { throw new LogicException('Step must be +ve'); }
for ($i = $start; $i <= $limit; $i += $step) { yield $i; } } else { if ($step >= 0) { throw new LogicException('Step must be -ve'); }
for ($i = $start; $i >= $limit; $i += $step) { yield $i; } } }
/* * Note that both range() and xrange() result in the same * output below. */
echo 'Single digit odd numbers from range(): '; foreach (range(1, 9, 2) as $number) { echo "$number "; } echo "
";
echo 'Single digit odd numbers from xrange(): '; foreach (xrange(1, 9, 2) as $number) { echo "$number "; }

Я увеличил количество генераций до 100000
range(): https://repl.it/Fy4I xrange(): https://repl.it/Fy4K
Результат мало чем отличается. Я полагал, что при использовании xrange() памяти должно быть потреблено меньше. Почему так?


Ответ

Потому, что вы забыли использовать результат
Надо так:
$a=range(0, 100000);
4474.390625
https://repl.it/Fy4I/1
Создался полный набор значений.
$a=xrange(0, 100000);
377.7890625
https://repl.it/Fy4K/1
Извлечено только одно значение.

Регулярное выражение по HTML

У меня есть такой HTML-код:


Я составил для этого кода регулярное выражение:
\\\\\<\/div\>
Но оно, почему-то, пишет, что нет совпадений. Кто знает в чём дело?


Ответ

Для манипуляций с HTML лучше пользоваться HTML-парсером. Вот пример использования PHP DomDocument для удаления определенных тегов вместе с их содержимым:
$html = <<

Start

DATA;
$dom = new DOMDocument('1.0', 'UTF-8'); // Инициализация DOMDocument $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); // Заполнение структуры данными
$xpath = new DOMXPath($dom); // Инициализация DOMXPath нашими данными $divs = $xpath->query('//div[@id="community_header" and @class="wcommunity_header"]'); // Запрос XPath
foreach ($divs as $div) { $div->parentNode->removeChild($div); // Удаление найденных элементов }
echo $dom->saveHTML();
См. демо этого кода
Запрос XPath означает:
//div - найди все div, в которых [@id="community_header" - атрибутidравенcommunity_header` and - а также @class="wcommunity_header"] - атрибут class равен wcommunity_header

Странное поведение ограничений в обобщенном методе

Всем доброго времени суток. Может быть кто-то уже сталкивался с таким и может помочь?
public static class JSON { public static string Serialize_object_TO_JSON(this T Entity) where T:ENT { return JsonConvert.SerializeObject(Entity); }
}
Есть некий класс, который наследует ENT и передавать его в атрибуты можно. Дальше мне пришлось переделать метод так, чтоб она работал с коллекциями:
public static class JSON { public static string Serialize_object_TO_JSON(this T Entity) where T:List { return JsonConvert.SerializeObject(Entity); }
}
После чего компилятор говорит, что ему не удалось привести тип класса, который наследуется от ENT, к типу List.
P.S. Изначально задавать обобщение конечного класса я не могу, т.к. их довольно много, именно по этому попытался делать через наследование.


Ответ

Попробуйте так, если Вам это разрешает бизнес логика:
public static class JSON { public static string Serialize_object_TO_JSON(this T Entity) where T : IEnumerable { return JsonConvert.SerializeObject(Entity); } }
Дело в том что List - инвариантен. И все классы в .NET инвариантны. То есть это полное соответствие типов.
Означает, что можно использовать только изначально заданный тип. Таким образом, параметр инвариантного универсального типа не является ни ковариантным, ни контравариантным.
С другой стороны есть IEnumerable где тип-параметр T помечен как out - ковариантным.
Позволяет использовать тип с большей глубиной наследования, чем задано изначально.
Полное описание почему так
+1 за хороший пример

Рандом в крестиках ноликах

Я сделал простую версию игры крестики нолики. При нажатии на ячейку, в ней появляется крестик и вызывается функция, что бы поставить нолик рандомно.
Я добавил условие, что если ячейка не пустая, то ничего не ставить. С крестиком это срабатывает, а вот с ноликом нет. Если ячейка занята то оно ничего вообще не ставит. Как можно нормально это поправить?
$(function() { var bot = function() { var cell = Math.floor(Math.random() * (10 - 1)) + 1; if( $('.board-cell').eq(cell).text() == '' ) $('.board-cell').eq(cell).text( 'O' ); }; $('.board-cell').click(function() { if( $(this).text() == '' ){ $(this).text( 'X' ); bot(); }; }); }); .board { display: flex; flex-wrap: wrap; width: 153px; height: 153px; border-left: 1px solid black; border-top: 1px solid black; } .board-cell { width: 50px; height: 50px; border-right: 1px solid black; border-bottom: 1px solid black; cursor: pointer; }



Ответ

Можно так:
$(function() { function bot() { var $cells = $('.board-cell:empty'); var i = Math.floor(Math.random() * $cells.length); $cells.eq(i).text( 'O' ); }; $('.board-cell').click(function() { if( $(this).text() == '' ){ $(this).text( 'X' ); bot(); }; }); }); .board { display: flex; flex-wrap: wrap; width: 153px; height: 153px; border-left: 1px solid black; border-top: 1px solid black; } .board-cell { width: 50px; height: 50px; border-right: 1px solid black; border-bottom: 1px solid black; cursor: pointer; }


await Task не содержит определение Delay

using System.Threading.Tasks;
private async Task PageLoad(int TimeOut) { TaskCompletionSource PageLoaded = null; PageLoaded = new TaskCompletionSource(); int TimeElapsed = 0; _webBrowser.DocumentCompleted += (s, e) => { if (_webBrowser.ReadyState != WebBrowserReadyState.Complete) return; if (PageLoaded.Task.IsCompleted) return; PageLoaded.SetResult(true); };
while (PageLoaded.Task.Status != TaskStatus.RanToCompletion) { TimeElapsed++; if (TimeElapsed >= TimeOut * 100) PageLoaded.TrySetResult(true); await Task.Delay(10); } }
Почему VS пишет что Task не содержит определение для Dеlay? Вроде для ее работы нужна только System.Threading.Tasks или опять что-то поменялось?


Ответ

Task.Delay доступен с версии .NET Framework 4.5.
Есть аналог для .NET Framework 4 в реализации Microsoft Async
использовать так:
await TaskEx.Delay(1000);

Ошибка: play() can only be initiated by a user gesture (мобильный Chrome)

Делаем приложение через Ionic/Cordova; компилю на платформу browser; через библиотeку медиа пытаюсь запустить мелодию по событию (пришел заказ от клиента).
Столкнулся с такой проблемой: если PUSH работает нормально, то на попытку инициализировать звук когда открыто приложение через мобильный хром — ну ни как не получается. Вылетает такая ошибка:
Uncaught (in promise) DOMException: play() can only be initiated by a user gesture.
И да, я читал, что это такое и немного вот об этом и этом
Понаходил советы, что нужно вызов проигрывания цеплять на click или другой жест. Но, при всех прочих, захожу в ВК с мобильного браузера, смотрю на страницу — мне присылают сообщение, и звук идёт (не от PUSH, а от браузера)!
Вопрос: как у них это получилось? И как мне сделать такое же (хотя бы в теории)? Буду рад любым идеям. Спасибо.


Ответ

function initAudioItems(e) { if (e.originalEvent !== undefined) { var dom_item = document.getElementById('my_audio'); dom_item.muted = true; dom_item.play() .catch(function(e) { console.log(e); }); dom_item.pause(); dom_item.muted = false; $(dom_item).data('init', true); $('body').off('click', initAudioItems); } } // init audio $('body').on('click', initAudioItems);
Если пользователь хоть раз кликнет на странице - аудио беззвучно запустится и остановится. После этого вы можете запускать его по произвольному событию.
Как ни старался не смог найти как такую инициализацию повесить на пролистывание, только на клик работает.

Как сделать плавную смену css градиента при наведении

Как можно сделать плавную смену фона (градиент на градиент) при наведении hover на элемент. Сделал кнопку, дал ей все необходимые стили, включая transition для плавности эффекта наведения, но при этом смена фона происходит резко, а все остальные эффекты в виде изменения тени, как положено меняются плавно.
.btn_default { display: inline-block; min-width: 200px; font-family: $bold; font-size: 1.125em; margin-top: 10px; padding: 13px 20px; text-align: center; color: #fff; outline: none; border-radius: 30px; background: linear-gradient(0deg, rgb(158, 48, 160), rgb(213, 80, 298)); box-shadow: 0 2px 7px rgba(213, 80, 208, 0.6); transition: all 0.5s; } .btn_default:hover { color: #fff; text-decoration: none; background: linear-gradient(0deg, rgb(101, 31, 102), rgb(173, 65, 169)); box-shadow: 0 2px 10px rgba(213, 80, 208, 0.9); } Some link


Ответ

Как вариант
.btn_default { display: inline-block; min-width: 200px; font-family: $bold; font-size: 1.125em; margin-top: 10px; padding: 13px 20px; text-align: center; color: #fff; outline: none; border-radius: 30px; background: linear-gradient(0deg, rgb(158, 48, 160), rgb(213, 80, 298)); box-shadow: 0 2px 7px rgba(213, 80, 208, 0.6); position: relative; } .btn_default > span{ position: relative; z-index: 1; } .btn_default:after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; color: #fff; text-decoration: none; background: linear-gradient(0deg, rgb(101, 31, 102), rgb(173, 65, 169)); box-shadow: 0 2px 10px rgba(213, 80, 208, 0.9); border-radius: 30px; opacity: 0; transition: opacity 0.5s; } .btn_default:hover:after { opacity: 1; } Some link