Скачал такой сегмент, внутри mp3. Не лучше будет минимизировать реенкод, добавив -c copy к флагам ffmpeg? Неизвестно, сколько уже раз файл перекодировался на стороне самого vk (при загрузке, при нарезке в HLS). Конечно, если среди сегментов не только mp3 попадаются, нужно будет перекодировать, но это легко проверить тем же ffmpeg/ffprobe.
Этот "ужас" — просто псевдокод, чуть-чуть приближенный к математике по синтаксису. Демонстрация подхода. Про хардкод скорее относится к фрагментам кода конкретно из этой части статьи, а именно к аналитическим солверам. Вы сами демонстрируете фрагменты с switch (func.Name) { case "sinf" ... }, собственно, вот. Здесь есть над чем поработать.
У Mathematica прекрасная документация. Так что многие вещи можно вынести оттуда. Есть достаточно много открытых проектов и на ней. В т.ч. всякие пакеты символьных вычислений над тензорами — вот где нужен хороший pattern matching! Я в свое время тоже с этим игрался в математике (маленький самописный тензорный движок) и был почти доволен.
Не знаю, поможет ли автору мой комментарий, но поскольку сам был вдохновлен подобной идеей когда-то (до практики руки не дошли), накопились некоторые соображения по теме. Я имел неплохой опыт работы с Wolfram Language и большинство замечаний будут так или иначе связаны с ним. Также спешу заметить, что в репозиторий с кодом я так и не заглянул, потому если что-то уже именно так и реализовано, но в статье не отражено (или я не понял) — оно и к лучшему (надеюсь).
Во-первых. Pattern matching — прекрасная концепция функциональных языков. И она же по сути является краеугольным камнем любых символьных манипуляторов. (Может быть дело пойдет проще в F#?) В примере из предыдущей статьи с "уплощением" дерева для операции + (т.е. перевод x + (y + ...) в x + y + ...) автор вынужден был использовать слишком общие паттерны вроде any, const, Num(1) и т.д. Т.е. никак нельзя взять и сопоставить целое поддерево. Было бы куда проще, если бы можно было задавать правила не вида
if expr == plus(const1, any1) && any1 == plus(const2, any2)
а прямо-таки
if expr == plus(any1, plus(any2, any3))
Для сравнения, так оно в Mathematica и реализовано. Сопоставить одно выражение с другим очень и очень просто:
Несложно и заменить все вхождения данного паттерна в дереве:
plus[1, plus[2, plus[3, 4]]] //. plus[x___, plus[y__], z___] :> plus[x, y, z]
(* prints plus[1, 2, 3, 4] *)
Плюс, поскольку такие общие (x___ в частности) паттерны все-таки довольно накладны, математика из коробки предлагает т.н. атрибуты. Например, атрибут Flat, будучи присвоен функции plus, лишает нас необходимости самим ее уплощать.
Если бы можно было писать произвольные паттерны и доставать из них все упоминающиеся переменные (plus(a_, b_) => {a = ..., b = ...}), все бы существенно упростилось.
Во-вторых. Что касается упрощений, тут дело гораздо сложнее. Расширенный pattern matching, конечно, поможет, но шаблоны могут быть довольно сложные. Опять же, математика решает этот вопрос в Simplify и FullSimplify путем перебора всех возможных комбинаций подвыражений данного выражения: к каждой комбинации применяется та или иная упрощающая тактика, оценивается качество упрощения. Про качество тоже отдельный разговор. Например, можно минимизировать количество листов дерева выражения. Или длину максимальной ветви дерева. Играя с этим, можно делать интересные вещи.
В Simplify применяются некоторые эвристики, так что не все комбинации выражений действительно берутся в расчет. Вот пример вывода шагов упрощения выражения x^2 + 2x + a + 1 до a + (1 + x)^2 (вывод FullSimplify будет куда длиннее; к сожалению, я не знаю способа вывести это в формате "до-после", тут только "до"):
1 + a + 2 x + x^2
2 x
x^2
1 + 2 x + x^2
(1 + x)^2
1 + x
a + (1 + x)^2
...
Код получения такого вывода:
Simplify[x^2 + 2 x + a + 1, TransformationFunctions -> {Echo, Automatic}]
Как выражать правили замены? Думаю, также, как и сейчас — паттернами. Создается список элементарных упростителей. Далее перебором комбинаций подвыражений (поддеревьев т.е.) производятся попытки упрощения каждым упростителем. Из-за закрытых исходников математики мой интерес в этой области остался неудовлетворенным.
В-третьих. Я, конечно, понимаю, что проект скорее учебный, но все же зашивать упростители и решатели для конкретных функций прямо в код — не дело. Набор гибких паттерн-ориентированных упростителей существенно улучшит качество продукта, да и позволит добавлять новые функции на лету. Может даже для этого какой язык можно придумать простенький.
В-четвертых. Раньше уже упоминали, что можно компилировать выражения прямо в IL-код или в какие-нибудь нативные представления AST (Expressions). Математика тоже так может, плюс она может и в машинный код. Где-то на хабре была статья о компиляции математических функций в IL, но, боюсь, ту, о которой помню, не найду. Вот другая.
В-пятых. Вообще я был вдохновлен подходом интерактивных proof assistant'ов (Coq, The KeY Project, Z3 и т.д.). И прямо-таки горел желанием что-то свое написать. Но не срослось, поскольку я оценил объем работ неподъемным. Идея была в том, чтобы на каждом из этапов упрощения позволять пользователю выбирать ту тактику упрощения, которая бы ему была более приемлема. Из вычислителя-упростителя система тогда превращается в настоящую систему компьютерного доказательства. Мы выдвигаем гипотезу, что \forall x . sin(x)^2 + cos(x)^2 = 1, доказываем ее как-либо и оформляем в виде теоремы основн_триг_тождество. Далее уже можно на нее ссылаться, чтобы упростить sqrt(1 - sin^2(x)), заменив, например, 1. С группировкой тактик и теорем по категориям и с добавлением изрядной доли эвристик можно даже пользователя привлекать минимально к процессу доказательства. Проблем здесь много — чего только стоит контекст (например, теорема верна, если только x \in \Reals или x \in \Complex), потому я не буду сильно много здесь размышлять.
В-шестых. Хорошо бы на каком-либо этапе более детально осмотреться. Я имею в виду, например, подсмотреть у Mathematica и у готовых open source продуктов (у Axiom есть прямо-таки теоретические материалы, правда на поверку весьма скудные, где, кроме прочего, есть и аннотированные исходники). К сожалению, по вопросам систем компьютерной алгебры (СКА, CAS) крайне мало подробной информации (во всяком случае мне попадалось).
А вот поддержка на уровне языка (в виде расширения синтаксиса) может и была бы интересна.
Я бы так не сказал. Посмотрите на C#. Во что он превратился. В него тащут все, что считают полезным, и это печально. Сложно сохранять парадигму языка, постоянно навешивая новые языковые конструкции, которые порой только ухудшают восприятие кода. Сокращая количество часов на ввод кода мы увеличиваем в несколько раз количество часов на последующий анализ этого кода нами самими и/или другими разработчиками. Получается какой-то зоопарк конструкций, где еще и совершенно разные по смыслу вещи могут обозначаются одинаково/слишком похоже в разных контекстах. Хотя не секрет, что не для всего это верно.
Но это в целом. Что же касается оператора Элвиса, не считаю конкретно его необходимым на уровне языка, даже при том, что он весьма удобен. И хотя он и удобен, мы теряем контроль над потоком управления, получаем дополнительную сложность в отладке, дополнительный оверхед при чтении таких конструкций, особенно в случае длинных цепочек вида a?.b.c?.d?:e. Повторюсь, не стоит тащить все, что удобно, в язык, тем более такой консервативный язык, как java.
Кроме стримов он пока нигде не используется. Не использовался. До Java 9. С Java 9 он начал появляться в новых APIшках. Местами в старых. ServiceLoader, например, где он как раз и уместен — те самые "источники данных", о которых я упоминал ранее. Но в целом Optional сейчас есть только в стримах и в фишках вокруг них.
В том-то и дело, что в java это совершенно новая вещь, которая ни разу не интегрирована со стандартной библиотекой и тем более не имеет поддержки на уровне языка (боже упаси). Это, в общем-то, и вынуждает нас идти на некие уступки и не использовать повально Optional везде, где это только можно, возможно, было бы удобно.
Не со всеми примерами данного цикла статей я согласен. А вот с Brian Goetz (судя по приведенному высказыванию в переводе автора) — напротив.
Optional не стоит злоупотреблять. Он точно не должен быть полем класса. Хотя бы из приведенных в статье соображений.
Он уж точно не должен возвращаться геттерами полей класса. Геттеры должны быть прозрачными, а не плодить лишние обертки.
Он не должен использоваться в прозрачных сеттерах полей.
Его не надо использовать там, где это ведет к загромождению интерфейса и к увеличению объема кода со стороны пользователя. Яркий пример — Map-ы, List-ы и им подобные. Ни в коем случае нельзя возвращать Optional на запрос значения по ключу/индексу, если пользователь явно не попросил вернуть именно Optional.
Что касается значений по умолчанию, то использовать или нет здесь Optional — весьма спорный вопрос. Классический вариант с null, 0 или -1 чаще оказывается нагладнее и правильнее. Да, Optional "безопаснее", т.е. он подстегивает программиста проверять, действительно ли значение есть, а также избавляет от магических чисел, но какой ценой… Ценой подсовывания вместо реального объекта обертки над ним! А это, знаете ли, протекание реализации в контракт метода, причем не самое хорошее. Возможность возврата или установки null должна быть оговорена в контракте метода, но именно оговорена (задокументирована, зааннотирована), а не обернута в Optional или еще что-то.
Что касается NullPointerException (NPE в народе), то это вполне штатная ситуация времени разработки. Я считаю, что проверка на null входных значений (сеттеров, методов, конструкторов) всегда должна присутствовать в явном или неявном виде. Для этого даже стандартных helper-метод есть. Бояться словить или бросить NPE не надо. Просто условия их возникновения или не возникновения, как ранее было сказано, должны присутствовать в контракте метода. И не в виде Optional, поскольку это сбивает с толку, заставляет оборачивать аргументы в Optional насильно, а также приводит к полной неразберихе, когда в старых кусках кода значения по умолчанию обозначается через null, а в новых — уже гордо через Optional. Кроме того, планирование интерфейсов усложняется. И тут может закрасться мысль вообще все оборачивать в Optional...
Вот в каких случаях использование Optional действительно целесообразно и оправдано:
Стримы.
Методы-генераторы или источники данных. Например, получение (первого) объекта из БД по запросу. Здесь Optional будет выглядеть элегантнее null или xxxOrDefault. Про коллекции см. выше.
(Сомнительно и с опаской) Конструкторы и методы изменения состояния (в отличие от прозрачных сеттеров). См. Socket. Однако переусердствовать тоже не стоит. В прозрачные сеттеры и прозрачные конструкторы лучше все-таки по старинке передавать null. А логику переключения состояния, если какой-то объект устанавливается в null/Optional.empty() — по старинке обрабатывать отдельным методом или прописать поведение в контракте (что не всегда приемлемо).
Других возможностей его применения я не вижу. Возможно, пока. Кстати, что очень спорно, Optional можно применить в коллекциях, которые не переваривают null. Но это из разряда "приятный бонус" и к практике, вероятно, имеют мало отношения.
Ну, возможно, Вы и правы. За счет сужения области применения получаем более оптимальную трансляцию. (Но, опять же, не компиляцию.)
Честно говоря, я всегда был убежден, что синтаксические конструкции — просто синтаксический сахар. Те же async/await в Boost прекрасно "эмулируются" переключением контекстов (Boost.Context)...
Надо будет как-нибудь попробовать Ваш инструмент в деле, чтобы не разглагольствовать попусту)
Сразу скажу, что я не являюсь сколь-нибудь квалифицированным специалистом по части "гетерогенных" вычислений (на кластере, на GPU и т.д.). Вот несколько мыслей, которые мне удалось из прочитенного и понятого сформулировать.
"Инвазивный подход" требует изменения синтаксиса языка, наличие транслятора/препроцессора/особую поддержку в компиляторе. Это снижает управляемость тем, что происходит за занавесом, со стороны программиста. Плохо продуманные синтаксические конструкции могут породить другие синтаксические конструкции, чтобы закрыть дыры в первых.
Как уже отмечалось, ручное распараллеливание дает большую управляемость процессом, потенциально более расширяемо, в т.ч. и на поддержку кластерных и векторных вычислений. При наличии хорошего API тоже можно все записывать единообразно.
Не понятно, как вообще компилятор / препроцессор будет организовывать работу в кластере.
По поводу оптимизаций компилятора сказать ничего не могу, но как-то интуитивно — особой разницы не будет. Поле для оптимизаций ведь у нас не очень большое — мне только стек и видится (первый пример в статье, например). А эмуляция стека в коде и "нативный" стек в принципе отличаются только тем, что при переполнении стековой памяти легко получить stack overflow. Поправьте, если несу бредятину)
Честно говоря, не очень понятно, зачем такие сложности — расширение языка. Да и чем подход радикально отличается от "классического" распараллеливания на общем пуле потоков (кроме того, что это делается вручную, а не автоматически)? Какой-то выделенной поддержкой векторных вычислителей и тем, что все детали реализации очереди сокрыты от пользователя? Поясните, пожалуйста.
С этим не спорю. Сюда же дополнительный профит в виде отсутствия затрат на отрисовку страниц.
Так что прощай Java, прощайте тесты на Python'е, прощай Selenium.
Однако автор, по моему скромному мнению, ощутимо более существенным выделяет тезис именно против Selenium и "скачков" из рабочего окружения (js) в тестировочное (java и т.д.), а главное событие — появление headless browser — как-то скралось на его фоне...
Странно, что вообще gui-free-режимы в браузерах стали появляться только сейчас. Автотесты вроде бы уже давно практикуются. И если разработчики тех же firefox и opera подключатся к тренду (в чем я немного сомневаюсь, во всяком случае в плане сроков ожидания данной фичи), то будет великое счастье уже всем тестировщикам и всем тем, кто так или иначе связан с написанием и развертыванием этих тестов.
Вот что мне не понятно, так это что мешало раньше использовать все то же самое с chrome в "обычном" режиме, если так не хотелось использовать Java+Selenium? Разъясните, пожалуйста.
Скачал такой сегмент, внутри mp3. Не лучше будет минимизировать реенкод, добавив
-c copy
к флагам ffmpeg? Неизвестно, сколько уже раз файл перекодировался на стороне самого vk (при загрузке, при нарезке в HLS). Конечно, если среди сегментов не только mp3 попадаются, нужно будет перекодировать, но это легко проверить тем же ffmpeg/ffprobe.Этот "ужас" — просто псевдокод, чуть-чуть приближенный к математике по синтаксису. Демонстрация подхода. Про хардкод скорее относится к фрагментам кода конкретно из этой части статьи, а именно к аналитическим солверам. Вы сами демонстрируете фрагменты с
switch (func.Name) { case "sinf" ... }
, собственно, вот. Здесь есть над чем поработать.У Mathematica прекрасная документация. Так что многие вещи можно вынести оттуда. Есть достаточно много открытых проектов и на ней. В т.ч. всякие пакеты символьных вычислений над тензорами — вот где нужен хороший pattern matching! Я в свое время тоже с этим игрался в математике (маленький самописный тензорный движок) и был почти доволен.
Не знаю, поможет ли автору мой комментарий, но поскольку сам был вдохновлен подобной идеей когда-то (до практики руки не дошли), накопились некоторые соображения по теме. Я имел неплохой опыт работы с Wolfram Language и большинство замечаний будут так или иначе связаны с ним. Также спешу заметить, что в репозиторий с кодом я так и не заглянул, потому если что-то уже именно так и реализовано, но в статье не отражено (или я не понял) — оно и к лучшему (надеюсь).
Во-первых. Pattern matching — прекрасная концепция функциональных языков. И она же по сути является краеугольным камнем любых символьных манипуляторов. (Может быть дело пойдет проще в F#?) В примере из предыдущей статьи с "уплощением" дерева для операции + (т.е. перевод x + (y + ...) в x + y + ...) автор вынужден был использовать слишком общие паттерны вроде
any
,const
,Num(1)
и т.д. Т.е. никак нельзя взять и сопоставить целое поддерево. Было бы куда проще, если бы можно было задавать правила не видаа прямо-таки
Для сравнения, так оно в Mathematica и реализовано. Сопоставить одно выражение с другим очень и очень просто:
Несложно и заменить все вхождения данного паттерна в дереве:
Плюс, поскольку такие общие (
x___
в частности) паттерны все-таки довольно накладны, математика из коробки предлагает т.н. атрибуты. Например, атрибутFlat
, будучи присвоен функцииplus
, лишает нас необходимости самим ее уплощать.Если бы можно было писать произвольные паттерны и доставать из них все упоминающиеся переменные (
plus(a_, b_) => {a = ..., b = ...}
), все бы существенно упростилось.Во-вторых. Что касается упрощений, тут дело гораздо сложнее. Расширенный pattern matching, конечно, поможет, но шаблоны могут быть довольно сложные. Опять же, математика решает этот вопрос в
Simplify
иFullSimplify
путем перебора всех возможных комбинаций подвыражений данного выражения: к каждой комбинации применяется та или иная упрощающая тактика, оценивается качество упрощения. Про качество тоже отдельный разговор. Например, можно минимизировать количество листов дерева выражения. Или длину максимальной ветви дерева. Играя с этим, можно делать интересные вещи.В
Simplify
применяются некоторые эвристики, так что не все комбинации выражений действительно берутся в расчет. Вот пример вывода шагов упрощения выраженияx^2 + 2x + a + 1
доa + (1 + x)^2
(выводFullSimplify
будет куда длиннее; к сожалению, я не знаю способа вывести это в формате "до-после", тут только "до"):Код получения такого вывода:
Как выражать правили замены? Думаю, также, как и сейчас — паттернами. Создается список элементарных упростителей. Далее перебором комбинаций подвыражений (поддеревьев т.е.) производятся попытки упрощения каждым упростителем. Из-за закрытых исходников математики мой интерес в этой области остался неудовлетворенным.
В-третьих. Я, конечно, понимаю, что проект скорее учебный, но все же зашивать упростители и решатели для конкретных функций прямо в код — не дело. Набор гибких паттерн-ориентированных упростителей существенно улучшит качество продукта, да и позволит добавлять новые функции на лету. Может даже для этого какой язык можно придумать простенький.
В-четвертых. Раньше уже упоминали, что можно компилировать выражения прямо в IL-код или в какие-нибудь нативные представления AST (Expressions). Математика тоже так может, плюс она может и в машинный код. Где-то на хабре была статья о компиляции математических функций в IL, но, боюсь, ту, о которой помню, не найду. Вот другая.
В-пятых. Вообще я был вдохновлен подходом интерактивных proof assistant'ов (Coq, The KeY Project, Z3 и т.д.). И прямо-таки горел желанием что-то свое написать. Но не срослось, поскольку я оценил объем работ неподъемным. Идея была в том, чтобы на каждом из этапов упрощения позволять пользователю выбирать ту тактику упрощения, которая бы ему была более приемлема. Из вычислителя-упростителя система тогда превращается в настоящую систему компьютерного доказательства. Мы выдвигаем гипотезу, что
\forall x . sin(x)^2 + cos(x)^2 = 1
, доказываем ее как-либо и оформляем в виде теоремыосновн_триг_тождество
. Далее уже можно на нее ссылаться, чтобы упроститьsqrt(1 - sin^2(x))
, заменив, например, 1. С группировкой тактик и теорем по категориям и с добавлением изрядной доли эвристик можно даже пользователя привлекать минимально к процессу доказательства. Проблем здесь много — чего только стоит контекст (например, теорема верна, если толькоx \in \Reals
илиx \in \Complex
), потому я не буду сильно много здесь размышлять.В-шестых. Хорошо бы на каком-либо этапе более детально осмотреться. Я имею в виду, например, подсмотреть у Mathematica и у готовых open source продуктов (у Axiom есть прямо-таки теоретические материалы, правда на поверку весьма скудные, где, кроме прочего, есть и аннотированные исходники). К сожалению, по вопросам систем компьютерной алгебры (СКА, CAS) крайне мало подробной информации (во всяком случае мне попадалось).
Я бы так не сказал. Посмотрите на C#. Во что он превратился. В него тащут все, что считают полезным, и это печально. Сложно сохранять парадигму языка, постоянно навешивая новые языковые конструкции, которые порой только ухудшают восприятие кода. Сокращая количество часов на ввод кода мы увеличиваем в несколько раз количество часов на последующий анализ этого кода нами самими и/или другими разработчиками. Получается какой-то зоопарк конструкций, где еще и совершенно разные по смыслу вещи могут обозначаются одинаково/слишком похоже в разных контекстах. Хотя не секрет, что не для всего это верно.
Но это в целом. Что же касается оператора Элвиса, не считаю конкретно его необходимым на уровне языка, даже при том, что он весьма удобен. И хотя он и удобен, мы теряем контроль над потоком управления, получаем дополнительную сложность в отладке, дополнительный оверхед при чтении таких конструкций, особенно в случае длинных цепочек вида
a?.b.c?.d?:e
. Повторюсь, не стоит тащить все, что удобно, в язык, тем более такой консервативный язык, как java.Кроме стримов он пока нигде не используется.Не использовался. До Java 9. С Java 9 он начал появляться в новых APIшках. Местами в старых. ServiceLoader, например, где он как раз и уместен — те самые "источники данных", о которых я упоминал ранее. Но в целомOptional
сейчас есть только в стримах и в фишках вокруг них.В том-то и дело, что в java это совершенно новая вещь, которая ни разу не интегрирована со стандартной библиотекой и тем более не имеет поддержки на уровне языка (боже упаси). Это, в общем-то, и вынуждает нас идти на некие уступки и не использовать повально
Optional
везде, где этотолько можно, возможно, было бы удобно.Не со всеми примерами данного цикла статей я согласен. А вот с Brian Goetz (судя по приведенному высказыванию в переводе автора) — напротив.
Map
-ы,List
-ы и им подобные. Ни в коем случае нельзя возвращатьOptional
на запрос значения по ключу/индексу, если пользователь явно не попросил вернуть именноOptional
.Что касается значений по умолчанию, то использовать или нет здесь
Optional
— весьма спорный вопрос. Классический вариант сnull
, 0 или -1 чаще оказывается нагладнее и правильнее. Да,Optional
"безопаснее", т.е. он подстегивает программиста проверять, действительно ли значение есть, а также избавляет от магических чисел, но какой ценой… Ценой подсовывания вместо реального объекта обертки над ним! А это, знаете ли, протекание реализации в контракт метода, причем не самое хорошее. Возможность возврата или установкиnull
должна быть оговорена в контракте метода, но именно оговорена (задокументирована, зааннотирована), а не обернута вOptional
или еще что-то.Что касается
NullPointerException
(NPE в народе), то это вполне штатная ситуация времени разработки. Я считаю, что проверка наnull
входных значений (сеттеров, методов, конструкторов) всегда должна присутствовать в явном или неявном виде. Для этого даже стандартных helper-метод есть. Бояться словить или бросить NPE не надо. Просто условия их возникновения или не возникновения, как ранее было сказано, должны присутствовать в контракте метода. И не в видеOptional
, поскольку это сбивает с толку, заставляет оборачивать аргументы вOptional
насильно, а также приводит к полной неразберихе, когда в старых кусках кода значения по умолчанию обозначается черезnull
, а в новых — уже гордо черезOptional
. Кроме того, планирование интерфейсов усложняется. И тут может закрасться мысль вообще все оборачивать в Optional...Вот в каких случаях использование
Optional
действительно целесообразно и оправдано:Optional
будет выглядеть элегантнееnull
илиxxxOrDefault
. Про коллекции см. выше.Socket
. Однако переусердствовать тоже не стоит. В прозрачные сеттеры и прозрачные конструкторы лучше все-таки по старинке передаватьnull
. А логику переключения состояния, если какой-то объект устанавливается вnull
/Optional.empty()
— по старинке обрабатывать отдельным методом или прописать поведение в контракте (что не всегда приемлемо).Других возможностей его применения я не вижу. Возможно, пока. Кстати, что очень спорно,
Optional
можно применить в коллекциях, которые не перевариваютnull
. Но это из разряда "приятный бонус" и к практике, вероятно, имеют мало отношения.После прочтения самой статьи того же мнения.
За что минусуем, товарищи? Мне тоже глаз режет. Хотя о таком все-таки лучше в личку.
Ну, возможно, Вы и правы. За счет сужения области применения получаем более оптимальную трансляцию. (Но, опять же, не компиляцию.)
Честно говоря, я всегда был убежден, что синтаксические конструкции — просто синтаксический сахар. Те же
async/await
в Boost прекрасно "эмулируются" переключением контекстов (Boost.Context)...Надо будет как-нибудь попробовать Ваш инструмент в деле, чтобы не разглагольствовать попусту)
Да, хотелось бы взглянуть на результат работы. Вы его описываете-описываете) Надо же пощупать. Что же это за такие "еще некоторые интересные вещи"?
Сразу скажу, что я не являюсь сколь-нибудь квалифицированным специалистом по части "гетерогенных" вычислений (на кластере, на GPU и т.д.). Вот несколько мыслей, которые мне удалось из прочитенного и понятого сформулировать.
"Инвазивный подход" требует изменения синтаксиса языка, наличие транслятора/препроцессора/особую поддержку в компиляторе. Это снижает управляемость тем, что происходит за занавесом, со стороны программиста. Плохо продуманные синтаксические конструкции могут породить другие синтаксические конструкции, чтобы закрыть дыры в первых.
Как уже отмечалось, ручное распараллеливание дает большую управляемость процессом, потенциально более расширяемо, в т.ч. и на поддержку кластерных и векторных вычислений. При наличии хорошего API тоже можно все записывать единообразно.
По поводу оптимизаций компилятора сказать ничего не могу, но как-то интуитивно — особой разницы не будет. Поле для оптимизаций ведь у нас не очень большое — мне только стек и видится (первый пример в статье, например). А эмуляция стека в коде и "нативный" стек в принципе отличаются только тем, что при переполнении стековой памяти легко получить stack overflow. Поправьте, если несу бредятину)
Честно говоря, не очень понятно, зачем такие сложности — расширение языка. Да и чем подход радикально отличается от "классического" распараллеливания на общем пуле потоков (кроме того, что это делается вручную, а не автоматически)? Какой-то выделенной поддержкой векторных вычислителей и тем, что все детали реализации очереди сокрыты от пользователя? Поясните, пожалуйста.
С этим не спорю. Сюда же дополнительный профит в виде отсутствия затрат на отрисовку страниц.
Однако автор, по моему скромному мнению, ощутимо более существенным выделяет тезис именно против Selenium и "скачков" из рабочего окружения (js) в тестировочное (java и т.д.), а главное событие — появление headless browser — как-то скралось на его фоне...
Странно, что вообще gui-free-режимы в браузерах стали появляться только сейчас. Автотесты вроде бы уже давно практикуются. И если разработчики тех же firefox и opera подключатся к тренду (в чем я немного сомневаюсь, во всяком случае в плане сроков ожидания данной фичи), то будет великое счастье уже всем тестировщикам и всем тем, кто так или иначе связан с написанием и развертыванием этих тестов.
Вот что мне не понятно, так это что мешало раньше использовать все то же самое с chrome в "обычном" режиме, если так не хотелось использовать Java+Selenium? Разъясните, пожалуйста.