• Корпоративная wiki - замена Confluence, какие есть варианты?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    - XWIKI
    - Wiki.js
    - trac
    Ответ написан
    Комментировать
  • Стоит ли использовать микрокомпьютер для удаленной работы?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Ох, тут уже на предлагали... Что ж, я не путешествую, но вопрос "куда можно запихнуть мини ПК" меня какое то время мучил, и я пришёл к выводу, что из мини ПК может получится неплохая ретро-консоль. И естественно она должна быть портативной. И раз вам так хочется сменить ноут на миник, то поделюсь к каким выводам я пришёл.
    1. Покупать что то излишне миниатюризированное формата raspberry Pi не стоит. Это вариант для умного дома и управления прочими прибамбасами, а не для работы или тем более игр. Естественно туда же идут и все варианты, напоминающие флэшку. При попытке работать будете плеваться от тормозов.
    2. Излишне тесный корпус приводит к нагреву и требует излишнего охлаждения. А это шум, доп потребление, механические детали и повышение стоимости . В тесных корпусах возможно только CPU с очень низким теплопакетом, а значит смотри пункт первый, тормоза неизбежны.
    3. Только не Андроид (и arm)! Не знаю кому как, а мне софта на адройде мало И практически отсутствует open source варианты. Так что и всякие планшеты и тв-боксы и подобный хлам - в лес. К тому же можно ещё испытать и прекрасный геморрой при попытке с планшета вывести изображение на монитор. Не все планшеты такое поддерживают.
    4. И не intel NUC или тем более его китайские собратья. В качестве самого NUC сомневаться не приходится. Однако, тем не менее, это проприетарная платформа и от ноутбука отличается только отсутствием монитора... Ничего толком не известно сколько будет стоить апгрейд и будет ли он вообще возможен. А спрашивается зачем тогда оно ? По этой же причине и не мак-мини и прочие надкусанности. Сюда же ещё и дефицит софта в сравнении с x86 как и у андройда.
    Итого: приходим к выводу, что это будет самосбор:
    Вариант 1: Корпус формата mini ITX - не слишком маленьких, что бы туда влезало типовое железо и небыло проблем с охладом и не слишком большой потому что портативность. Объём 2-5 литров. Плюсы:
    - можно собрать x86 на десктопном процессоре, с приличным объёмом оперативки и даже встроенным SSD приличного объёма (хотя уж с этим то сейчас проблем нет и полно внешних корпусов для SSD, но встроенный вы не будете искать среди кучи хлама после очередного переезда.
    - всё ещё поддается апгрейду, но занимает места примерно столько же сколько и ноут. Допускает относительно хорошее охлаждение Широкий выбор самих корпусов, как у именитых брендов так и китайцев. Полностью сменная начинка, которая никуда не исчезнет с рынка. И даже сменный процессор и память. И в тоже время - внешний БП как и в ноуте (правда без батареи, но как говорится, кто мешает и её воткнуть...), может оказаться полезной вещью в дороге, если нужно запитать ещё какие то низковольтные устройства от 12 вольт
    - Возможность втыкивать достаточно мощный процессор. Я присматривался к райзену с интегрированным GPU. На таком не только работать, но и во что то не сильно требовательное можно поиграть.
    - Можно настроить dual boot - windows + linux для тех кому нужно. Полноценная сеть (уже не во всех ноутбуках она есть. А во всяких малиноподобных вариантах - как правило, сеть медленная)
    - Широкий набор внешних портов. Любой ноут здесь проигрывает. (другой вопрос нужно ли это для вашей работы)
    - Прочный металлический корпус (полно как стальных, так и алюминивых вариантов. Есть и пластиковые, но я бы брал металл как из-за прочности так и из-за охлаждения)
    Минусы:
    - Цена Как говорится, из разряда "отложу как я это до лучших времён" С такими ценами, как сегодня, вообще не выгодно менять железо.
    - Надо собирать самому (ну для меня это не минус, а для вас - не знаю)
    - Размер и вес скорее всего будет немного больше того же Intel NUC но, считаю, что это не существенно.
    - мощность системы не должно превышать 150-200 ватт иначе будет перегреваться да и БП на такую мощность найти сложновато. Вполне можно уложиться если брать CPU с TDP 45-65 Ватт

    Вариант 2 Мощный самосбор в корпусе miniITX объёмом до 12 литров. Плюсы:
    - Всё тоже самое что и варианте 1 но немного дешевле т к корпус больше
    - Уже есть возможность запихнуть какой-никакой дискретный GPU Но тут надо заранее выбирать и велика вероятность того, что этот элемент потом обновлять будет тяжело, т к трёх-слотовый монстр длиной 30+ сантиметров туда не встанет, а среднебюджетных вариантов как то не видно на горизонте Только слабенькие GPU делают в усеченных размерах и их ещё найти нужно.
    - можно поставить очень хорошее охлаждение при желании. Но тоже нужно об этом думать на этапе выбора
    корпуса
    - Уже относительно стандартные внутренние БП на 300-500 ватт
    Минусы:
    - Вес. Если для вас не критично вес в несколько килограмм (сейчас только видяхи по килограмму весят =)
    - Размер 12 литров - это как два с половиной пятилитровых бутыля. Для сравнения, обычно корпуса ноутбуков не превышают 2-х литров. Очевидно, при авиаперелетах это скорее всего в багаж отправится...
    Ответ написан
    1 комментарий
  • Python, postgress, pandas - куда утекает память?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Я не специалист по пайтону, но присматриваюсь и ваш код меня заинтересовал. Немного погуглив я нашел такой похожий вопрос на SO ( https://stackoverflow.com/questions/39100971/how-d... ), но c более простым кодом:
    import pandas
    df = pandas.read_csv('large_txt_file.txt')
    del df

    Уже этого достаточно, что бы память не возвращалась в ОС. Автор вопроса подозревал Pandas, но как пояснили в ответах, это особенность самого пайтона:
    Reducing memory usage in Python is difficult, because Python does not actually release memory back to the operating system. If you delete objects, then the memory is available to new Python objects, but not free()'d back to the system (see this question).

    Т е если вы смотрите количество используемой процессом памяти, то оно будет только увеличиваться. Первое, что я бы попробовал, это поменять ваш код так:
    for station in config.STATIONS_LIST:
        sql_query = f"select * from table where  where station = '{station}'"
        df = pd.read_sql(sql_query, con=connection_pg)
        filename = f'data_{station}'
        filename_with_path = os.path.join(config.OUTPUT_PATH, filename)
        compression_options = dict(method='zip', archive_name=f'{filename}.csv')
        df.to_csv(f'{filename_with_path}.zip', compression=compression_options, index=False)
        <b>df = ' '</b>
        gc.collect()

    Т е не удалять переменную, а переприсвоить. Некоторые говорят, что это помогает (если честно, мне в такое с трудом верится, но я не знаю пайтона) Среди других рекомендаций: загружать данные меньшими порциями и офлоудить работу другому процессу, который затем убивается и память освобождается ОС. (на мой взгляд способ хороший, хоть и не слишком архитектурно-правильный, но гарантировано добавит стабильности и застрахует даже от будущих утечек, если они появятся либо в вашем коде либо в новых версиях библиотек)
    Другой вопрос, почему это увеличение не останавливается. Если это всё дело происходит на linux то я бы попробовал ограничить пайтону память (первое что нагуглилось: https://www.geeksforgeeks.org/python-how-to-put-li...) и посмотрел будет ли при этом интерпретатор умирать по причине недостатка памяти. Если будет, то на SO рекомендовали такое средство: https://mg.pov.lt/objgraph/ Этим можно посмотреть что именно потребляет память.
    Ответ написан
    5 комментариев
  • Какой Xeon выбрать под рабочую станцию для machine learning?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    А чем в этом плане Xeon вам поможет ? На мой взгляд лучше сэкономить и в итоге скопить денег на какой-нибудь GPGPU - вычислитель, типа NVIDIA TESLA или что там сейчас можно взять подешевле (возможно Б/У ) Причем выбирать по количеству памяти, чем больше тем лучше. Я не шибко большой спец в этом и может меня поправят, но на мой взгляд всё очень сильно замедляется когда модель для обучения перестаёт помещаться в память ускорителя. Процессор же в этом деле только косвенно участвует. С другой стороны я не знаю какие у вас будут модели, может их вообще на GPU не загнать...
    Ответ написан
  • На собеседовании сказали, что не все функции - замыкания. Так ли это?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Похоже вас поймали на том что в js кто-то решил переопределить термин "замыкание"... Т к javascript далеко не первый язык, в котором есть нечто, претендующее называться термином "замыкание", то следует в первую очередь рассмотреть общее определение. Возьмём его из википедии:

    Замыкание (англ. closure) в программировании — функция первого класса, в теле которой присутствуют ссылки на переменные, объявленные вне тела этой функции в окружающем коде и не являющиеся её параметрами. Говоря другим языком, замыкание — функция, которая ссылается на свободные переменные в своей области видимости.
    Замыкание, так же как и экземпляр объекта, есть способ представления функциональности и данных, связанных и упакованных вместе.
    Замыкание — это особый вид функции. Она определена в теле другой функции и создаётся каждый раз во время её выполнения. Синтаксически это выглядит как функция, находящаяся целиком в теле другой функции. При этом вложенная внутренняя функция содержит ссылки на локальные переменные внешней функции. Каждый раз при выполнении внешней функции происходит создание нового экземпляра внутренней функции, с новыми ссылками на переменные внешней функции.
    В случае замыкания ссылки на переменные внешней функции действительны внутри вложенной функции до тех пор, пока работает вложенная функция, даже если внешняя функция закончила работу, и переменные вышли из области видимости.[1]
    Замыкание связывает код функции с её лексическим окружением (местом, в котором она определена в коде). Лексические переменные замыкания отличаются от глобальных переменных тем, что они не занимают глобальное пространство имён. От переменных в объектах они отличаются тем, что привязаны к функциям, а не объектам.


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

    In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function[a] together with an environment.[1] The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created.[b] Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.


    О! А тут нет никаких "функций, вложенных в функцию" и нет никаких "создающихся каждый раз" Хм... Интересно. Ну за то есть абзац о том как появились замыкания:

    The concept of closures was developed in the 1960s for the mechanical evaluation of expressions in the λ-calculus and was first fully implemented in 1970 as a language feature in the PAL programming language to support lexically scoped first-class functions.[2]

    Peter J. Landin defined the term closure in 1964 as having an environment part and a control part as used by his SECD machine for evaluating expressions.[3] Joel Moses credits Landin with introducing the term closure to refer to a lambda expression whose open bindings (free variables) have been closed by (or bound in) the lexical environment, resulting in a closed expression, or closure.[4][5] This usage was subsequently adopted by Sussman and Steele when they defined Scheme in 1975,[6] a lexically scoped variant of Lisp, and became widespread.


    Ага. Оказывается первоначально они появились в такой не конвенциональной, с сегодняшней точки зрения VM, как SECD... И их создатель прямо говорит, что это код плюс данные. Далее термин применяют к лямбда-выражениям. Ничего не говорится, должны ли эти выражения возвращаться функцией, или достаточно того, что бы они захватывали переменные из своего лексического (или динамического, как в common lisp) окружения. Далее нам сообщают, что некие мистеры, Сасман и Стил, спустя каких то 11 лет добавили это в свой язык Scheme... Ну что же. Посмотрим замыкания в Scheme... А именно откроем книгу Сасмана и соавторов "Структура и интерпретация компьютерных программ" или "SICP" Первый раз (исключая содержание) слово "замыкание" встречается в главе 2 "Поcтроение абстракций c помощью данных"


    Важная идея в работе с составными данными — понятие замыкания (closure): клей для
    сочетания объектов данных должен позволять нам склеивать не только элементарные
    объекты данных, но и составные.


    Но, как выяснилось, это не те замыкания... Это замыкание в том смысле, что структуру одного типа (в данном случае пары) могут ссылаться на самих себя. И это то как термин "замыкание" понимают математики. Далее в SICP никаких других определений замыканий нет (несмотря на то, что само их использование конечно же есть) Ну ничего не остаётся как посмотреть что же сегодня называют замыканиями в языке Scheme... Гугл по этому запросу выдал первой ссылкой: https://www.cs.utexas.edu/ftp/garbage/cs345/schint....
    Цитирую:

    Procedures are Closures
    Scheme procedure's aren't really just pieces of code you can execute; they're closures.

    A closure is a procedure that records what environment it was created in. When you call it, that environment is restored before the actual code is executed. This ensures that when a procedure executes, it sees the exact same variable bindings that were visible when it was created--it doesn't just remember variable names in its code, it remembers what storage each name referred to when it was created.

    Since variable bindings are allocated on the heap, not on a stack, this allows procedures to remember binding environments even after the expressions that created those environments have been evaluated. For example, a closure created by a lambda inside a let will remember the let's variable bindings even after we've exited the let. As long as we have a pointer to the procedure (closure), the bindings it refers to are guaranteed to exist. (The garbage collector will not reclaim the procedure's storage, or the storage for the let bindings.)

    Here's an example that may clarify this, and show one way of taking advantage of it.

    Suppose we type the following expression at the Scheme prompt, to be interpreted in a top-level environment:

    Scheme> (let ((count 0))
               (lambda ()
                  (set! count (+ count 1))
                  count)))

    ##

    Evaluating this let expression first creates a binding environment with a binding for count. The initial value of this binding is 0. In this environment, the lambda expression creates a closure. When executed, this procedure will increment the count, and then return its value. (Note that the procedure is not executed yet, however--it's just created.) This procedure, returned by the lambda expression, is also returned as the value of the let expression, because a let returns the value of its last body expression. The read-eval-print loop therefore prints a representation of the (anonymous) procedure.


    Что имеем ? В Scheme - вообще любая функция - это замыкание! Т к она всегда захватывает контекст, даже если там пусто!. Что видим в коде ? Ну с точки зрения Scheme тут конечно вложенная функция, т к let - это на самом деле lambda, но так происходит потому, что в Scheme нет переменных в понимании js. В js же можно считать, что глобальный контекст - результат действия нечто, что эквивалентно let. Захватывает ли любая функция в js этот контекст ? Не знаю. Но точно знаю, что в вашем примере это определенно так - х часть контекста, который захватывается функцией. Кто хочет поспорить - идите спорьте с создателями Scheme (скажите, когда попкорн покупать, я посмотрю как вас пороть будут. Набежало тут вайтишников =)) Кто то может сказать "а вот у нас в js замыкания определяются не так" На что я отвечу: знаете, товарищи, а идите ка вы лесом! Если есть однажды созданный и определенный термин, нужны весьма веские причины что бы менять его определение. Желания левой ноги очередного вайтишника тут не достаточно.
    Ответ написан
    30 комментариев
  • Чем организовать очередь с возможностью поиска?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    То что было в очереди должно сохраняться ? Вроде 10000 записей - это не очень много и можно в памяти держать. Банально написать свою реализацию кольцевого буфера. При этом вынимаемый из середины элемент не удалять, а пометить как прочитанный, что бы когда до него дойдёт указатель конца, он его тупо пропустил.
    Ответ написан
    Комментировать
  • Я сделал Code Review, может быть я где-то ошибся или у вас есть что добавить?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Почему никто не спрашивает, что вообще делает class2 ? Т е что бы написать хороший ревью, надо хорошо понимать контекст использования этого кода. В остальном согласен с тем, что уже написали. Код писал студент-недоучка, а ревью - мидл, который не сумел изложить свои мысли. (уж простите, ничего личного). Я честно пытался разобрать что бы делал, прочитав такое ревью на свой код, и осознал что не могу понять примерно половину. Разумеется, в ревью надо объяснять всё как можно подробнее и с учётом того, кто будет читать. Если человек такой код написал, то очевидно, уровень подробностей должен быть максимальным. Более того, наверное имеет смысл сначала указать на главные ошибки, пусть он их исправит, а уже на втором ревью, в случае если он не насажает новых, что весьма и весьма вероятно, писать про имена переменных и код-стайл.
    Ну это мой подход. Конкретный интервьюер вполне может его и не разделять. Может у них "галера" и наличие даже одного "подхода" ревьюера - это роскошь. Так что вполне могу допустить, посчитали что "завалил", потому что и сами не в курсе как им оно надо.
    Ответ написан
    Комментировать
  • Как организовать хранение данных для новостной ленты социальной сети?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Как уже указал hint000 первый вариант можно использовать только очень ограниченно. Для второго лучше взять что-нибудь документо-ориентированное или мульти-колоночное, что позволит денормализовать структуру данных. Т е вам нужно хранить некое представление "обобщённой ленты" (возможно отдельно для каждой сферы, что бы потом это можно было шардировать) и там будут лежать эвенты в каждом из которых может быть записано много разной информации. Возможно какие то данные пользователей, для формирования их персональной ленты в момент запроса. В принципе и на базе postgres можно организовать такую таблицу, c большим количеством полей, плюс postgres умеет класть в колонки json, что может помочь. Но в любом случае лучше применить паттерн CQRS и исходные данные хранить нормализованными, а при их изменении бросать эвент, который пойдёт в RabbitMQ или Kafka и будет обрабатываться пулом инстансов, обновляющих записи в лентах. А раз так, то там вообще можно взять что-нибудь типа elastic search. На чтение она должна быть очень быстрой.
    хаос в разрешении всевозможных ситуаций: подписок, отписок, удалении постов и так далее.

    Наибольшую боль, как мне кажется, доставит удаление/блокировка контента, т к оно подразумевает обновление большого количества информации во всех лентах куда попало удаляемое. Вы можете пойти на компромисс и сделать, как делают многие - удаленные посты приходят в ленте как заглушка. В этом случае нет необходимости удалять их идентификаторы из лент, достаточно просто не выдавать их при запросах по айди. Плюс не ломается пагинация и не нужно изобретать велосипеда с бесконечными прокрутками (хотя если маркетойды настаивают, что так лучше, то нам же легче ))
    Ответ написан
    Комментировать
  • Как инвертировать строки в массиве, имплементировав интерфейс Function?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    В смысле, а чего тут непонятного ? У вас есть метод который на вход принимает String[] input, а выдать должен массив String[] но с инвертированными строками. Т е ровно тоже самое, что вы написали бы, если бы было так:
    public String[] reverseString(String[] input) {
    ...
    }
    Ответ написан
    Комментировать
  • Как гарантируется ACID в распределенных транзакциях (по мотивам мутной статьи)?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    внутри одной БД это реализуемо.

    Строго говоря, там точно также нет гарантий. Дисковая подситсема может сбойнуть в любой момент. К тому же сейчас диски часто сетевые...
    Так судя по комментам в этом топике, двухфазная фиксация или SAGA - это в принципе НЕ ТРАНЗАКЦИИ, т.е. никакой фактической транзакционности там нет?

    За SAGA не скажу, а вот двухфазная фиксация кроме того, что описано в статье, ещё должна, по идеи, так же как это делает отдельно стоящая СУБД, вести журнал логов перед началом транзакции. Возможно распределённый. Именно журнал (вернее его обработка) обеспечивает восстановление после аппаратных ( и в том числе сетевых сбоев). Сам же двухфазный комит гарантирует только то, что не будут записаны (и считаны до записи) несогласованные данные.
    Значит, любая система из связанных микросервисов априори не является надежной системой и всегда возможны потери данных?

    Да. Мир не идеален. Чем больше звеньев в цепочке отказа, тем выше вероятность этого самого отказа. Как все знают, эта вероятность равна произведению вероятностей каждого элемента. Т е проектируя микросервисную архитектуру вы можете посчитать вероятности отказа всех её составляющих, взяв за основу вероятности отказов аппаратуры или если есть, то более точно статистику отказов. И принять решение, можете вы на такое пойти или лучше оставить монолит в данном конкретном месте. Другое дело, что пока что я вижу по большей части "шапкозакидателльских" писунов микросервисов, которые их делают по принципу "потому что модно". Но как я полагаю, в банках всё же пока остались люди, которые понимают чем это грозит, иначе мы бы и банкоматами пользоваться перестали, потому что никому не охота ежедневно банку доказывать, что у них случился отказ...
    Ответ написан
    Комментировать
  • Не могу подключится к MSSQL через jdbc. Как исправить?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Откуда вы взяли этот useSSL=false ? Вот дока от микрософт по их jdbc драйверу https://docs.microsoft.com/ru-ru/sql/connect/jdbc/... Там никаких useSSL нет. За то есть encryption и trustServerCertificate Там даны различные варианты с описанием. Попробуйте их.
    Ответ написан
  • Какой 34 дюймовый монитор подойдёт для программирования?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Работаю на 32' дюйма 4K плоском. Всё устраивает в 2016 году уложился в 60 Сейчас цен не знаю, но сомневаюсь что в рублях они упали... Считаю, что для 32 дюймов 4K - это оптимально. Пикcелей ещё не видно, размер шрифта чуть увеличил в windows. Также важное значение имеют яркость и цветовое пространство, что бы монитор не давал "вырвиглазные" цвета. Хотя бы 80-90% sRGB что бы покрывалось. Изогнутость считаю не удобной, т к иногда нужно смотреть на монитор под другим углом, во избежание окосения.
    Ответ написан
    Комментировать
  • Как сделать VPS с собственным ip?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    с собственными ip адресами

    Мало подробностей, поэтому ответы такие.
    1. Нужен публичный ip (доступный из интернет ) или годится ip из локальной подсети (он будет доступен только с хоста с виртуалками или с хоста с виртуалками и локальной сети) ?
    2. Какая технология виртуализации ? (выше советовали VirtualBox, что не плохо т к возможно в нём настройки самые простые для этого: создаёте машины, идёте в настройки каждой VM (она должна быть выключена) -> Сеть -> выбираете "виртуальный адаптер хоста" По идеи на свежей установке виртуалбокса этого уже достаточно. При загрузке виртуальных машин он должен им раздать адреса через его собственный DHCP и они должны оказаться в одной сети, связанной с вашей тем самым адаптером, который был выбран. И на него также должен быть роздан адрес. Если же этого не происходит надо сходить в файл -> менеджер сетей хоста и там поставить адрес адаптера вручную и затем также вручную задать адреса уже в самих машинах.
    Ответ написан
    Комментировать
  • Как верно сгруппировать данные в запросе?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Затык в том, что условие WHERE построено не верно. Вложенный запрос вернет MAX('date') и это дата, а сравнивается это значение с good (который как я понимаю id)
    Я не знаю ваших данных, но предположу что в таблице item_good_supplies содержатся записи с одинаковым полем good и разной датой. В этом случае почему бы не воспользоваться group by ?:
    SELECT `good` AS `id`, /* `price`, */ MAX(`date`) as `date` 
    FROM `item_good_supplies` 
    WHERE `good` IN('23068', '21805', '23204', '22493', '21813', '21802', '23845')
    GROUP BY `good`


    Update:
    Как справедливо указал Rsa97 в комментарии, в этот запрос не получится впихнуть цену, т к good не является первичным ключом, а без этого необходимо указать price в group by, что приведёт к неверному результату. Если в таблице первичного ключа нет, то будет затруднительно составить запрос, который подставит корректную цену.
    Ответ написан
  • Поиск всех маршрутов графа C#?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    По-моему у вас рекурсия организована не совсем верно. Дело в том, что r передаётся по ссылке во все ветви поиска. И если одна из этих ветвей завершается успешно, r обнуляется, тем самым сбрасывая конкурирующие пути. Кроме того и в цикле поиска r так же должна всегда содержать тоже самое (т е путь до текущей вершины v. Но в вашем коде это не так, потому что r будет меняться внутри рекурсивного вызова.
    Я не уверен, что всё остальное правильно, но я бы поменял:
    dfs(a, ref visited, n, i, x, ref cnt, ref p, ref r);

    на
    dfs(a, ref visited, n, i, x, ref cnt, ref p,  r.ToArray());

    И соответственно ref убрал бы из определения dfs. Так при переходе по всем вершинам путям в цикле будет для каждого пути создана своя копия r. Так же в этом случае не нужен r.Remove(v + 1); и r = new List();
    Вообще передача большого количества аргументов по ссылке не очень хорошее решение с архитектурной точки зрения. Вам стоит подумать как организовать код так, что бы рекурсивная функция была "чистой" - т е её вызов с одними и теми же параметрами всегда приводил бы к одному результату. Умение писать в таком стиле сильно уменьшает вероятность ошибки.

    Update:
    По просьбе Michail7 привожу свой вариант решения:
    class Program
        {
    
            public  struct Path {
                public  List<int> Vertexes { readonly get;  private set; } 
                
                public Path(int vertex) {
                    this.Vertexes = new List<int>();
                    this.Vertexes.Add(vertex);
                }
    
                public Path(List<int> vertexes, int vertex) {
                    if (vertexes != null) {
                        this.Vertexes = new List<int>(vertexes);
                    }
                    else {
                        this.Vertexes = new List<int>();
                    }
                    this.Vertexes.Add(vertex);
                }
    
                public Path Add(int vertex) {
                    Path p = new Path(this.Vertexes, vertex);
                    return p;
                }
    
                public bool hasVertex(int vertex) {
                    return Vertexes.Contains(vertex);
                }
    
                public int LastVertex() {
                    return Vertexes.Last();
                }
            }
    
            public static List<Path> RunDfs(in  int[,] graph, int n, in Path currentPath, int targetVertex) {
                int currentVertex = currentPath.LastVertex();
                if (currentVertex == targetVertex) {
                    return new List<Path> { currentPath };
                }
                else {
                    List<Path> result = new List<Path>();
                    for (int i = 0; i < n; i++) {
                        if (graph[currentVertex,i] == 1 && ! currentPath.hasVertex(i) ) {
                            List<Path> newPaths = RunDfs(graph, n, currentPath.Add(i), targetVertex );
                            result.AddRange(newPaths);
                        }
                    }
                    return result;
                }
            }
    
            static void Main(string[] args) {
                int[,] graph =  { {0,1,1,0},{0,0,0,1},{0,1,0,0}, {0,0,0,0}};
                Path curPath = new Path().Add(0);
                List<Path> paths = RunDfs(graph, 4,  curPath, 3);
                Console.WriteLine("Hello World!");
            }

    Его наверняка можно улучшить. И не факт, что он по скорости выиграет. Но. В нём сведено к миниму количество параметров и метод RunDfs является "чистым" в том понятии, что для одинакового входа он всегда выдаёт тот же выход и не имеет сайд-эффектов в виде записи в передаваемые структуры. Единственное, что я не стал оптимизировать - это передачу графа в виде двумерного массива. Очевидно для настоящих больших графов так оставлять нельзя, т к есть вероятность, что компиллятор всё же решит его копировать по значению, несмотря на то, что запись внутри RunDfs в него не происходит. (Это наверное можно проверить, делая бенчмарки по времени на графе достаточного размера и сравнив версию, где граф передаётся через ref) Но правильнее и проще для графа также ввести какую то структуру или даже класс, который будет передаваться по ссылке, но при этом не будет давать себя менять.
    Ответ написан
    2 комментария
  • Линейная алгебра для компьютерного зрения?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Ну совсем без знаний эту задачу не решить. Надо хотя бы иметь представление о матрицах и операциях с ними. Остальное вполне могут сделать готовые библиотеки. Например: https://proglib.io/p/real-time-object-detection
    Ответ написан
    Комментировать
  • Существует ли зрение для робота без программирования?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    ну это ж бред в наше время, тратить ресурсы на такие базовые, по моему, вещи. Сам я, если что, хеловорлд на питоне или баше, ну может чуть больше.

    В этом мире вообще бреда много. И в том числе огромное количество закрытых корпоративных разработок , которые регулярно "переизобретаются" другими корпорациями. И, мало того, подаются как новое супер-пупер-революционное. И ещё есть при этом риск "наступить" на чей-нибудь патент, как на мину... Серьёзное обсуждение этой ситуации и почему она сложилась и при каких условиях можно это преодолеть - серьёзный вопрос, который затрагивает политические, социальные и даже философские аспекты, в которые тут не буду вдаваться.

    решения, позволяющие, условно, роботу на колесиках с Raspberry Pi и подключенной к нему камерой ездить по квартире и не врезаться, объезжать препятствия, видеть (пусть будет выделенный из окружения значок) свою зарядную станцию и заезжать на нее...

    Не долгое вспоминание и гугление дало следующие:
    1. ROS (Robot operating system):
    открытая платформа которую предполагается дополнять модулями для описанного в этом
    абзаце.
    - https://www.ros.org/ - офф сайт
    - https://en.wikipedia.org/wiki/Robot_Operating_System - википедия для быстрого ознакомления
    2. OpenVINO: Некая библиотека на основе нейронных сетей для частых задач по зрению роботов.
    - https://www.intel.com/content/www/us/en/developer/... Офф сайт
    - https://habr.com/ru/company/intel/blog/546438/ Статья на хабре (от студентов Не стоит многого ожидать)
    Опять же для быстрого ознакомления.
    - https://medium.com/the-research-nest/computer-visi... - тут кроме OpenVINO
    похожие проекты
    3. интеграция первого и второго.
    - https://github.com/intel/ros_openvino_toolkit

    ...иметь возможность малыми усилиями дополнять функционал ("робот, та херня, которую ты объехал заехав в комнату называется мяч, прикати его мне" ну как пример, можно проще).

    Вот это, боюсь, мало реально. Уж точно не силами Raspberry. Тут может понадобиться подкрепить усилия малыша тихо шумящим на заднем фоне супер-компьютером. Не из топ-500 конечно, но достаточно мощным, т к пока что с адаптацией нейросетей под новые задачи всё грустно - это делает человек с помощью перестройки архитектуры и обучения по новой (one-short learning конечно круто, но решает более простую задачу чем описанная). А как их связать с классическими алгоритмами понимания, логики и планирования - я даже работ таких не видел (они наверняка есть, но маркетологи о них не кричат, как об очередном говно-авто-художнике какого-нибудь сбера...)
    PS Я не сильно большой специалист в роботах, поэтому возможно это очевидные вещи или вообще не на что не годные проекты. Но по крайней мере это то, что есть в open source.
    Ответ написан
    Комментировать
  • Правильно ли я понял принцип инверсии зависимостей?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Посмотрите видео Александра Бындю по этой ссылке: https://blog.byndyu.ru/2013/06/blog-post_27.html (Это C# но в целом на Java очень похоже, поэтому должно восприниматься нормально) Он очень хорошо разворачивает там пример. После просмотра этого видео на код начинаешь смотреть по новому.
    Ответ написан
    Комментировать
  • Работает ли Asp.Net всегда?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Он не только работает "всегда", но имеет несколько режимов работы. Можно деплоить приложение как модуль IIS, так и сделать его stand alone. Первый вариант в свою очередь разделяется на два: "классический" и "интегрированный".

    1. Классический подразумевает что IIS загружает DLL модуль ISAPI который в свою очередь запускает NET-среду в отдельном потоке. Так что даже в этом случае ASP NET CORE (или более ранний ASP NET ) работает "всегда". (В отличие от просто ASP который был до NET). Не смотря на то, что на картинках в документации обработка начинается только с приходом запроса, там всё равно присутствует процесс и поток отвечающий за работу ASP NET. В нём запускается global.asax. Но этот процесс может быть в любое время перезапущен IIS, если хоть что то ему "не понравится" (включая, например что процесс был запущен слишком давно. Часть этих параметров доступна для изменения в пуле приложений IIS)

    2. В интегрированном режиме примерно всё тоже самое, за тем исключением, что там NET-среда уже является частью пайплайна IIS и приложению доступна возможность обрабатывать больше событий. Т к теперь это часть IIS, то штатным завершением будет выгрузка домена приложения из памяти. Но т к это может быть не возможно по разным причинам, IIS всё равно может перезапустить процесс вместе со всем пулом приложений. В штатном режиме обычно этого не происходит. Однако тут нужно сделать ремарку:
    Если под понятием "работает всегда" понимать запуск какой-то своей бэкграунд-задачи в отдельном потоке, то есть нюансы. Для старого ASP NET это описано в этом блоге haacked.com/archive/2011/10/16/the-dangers-of-impl... Для ASP NET CORE Микросософт сделал усилие и расширил как саму возможность правильного запуска фоновых задач, так и документацию: https://docs.microsoft.com/ru-ru/aspnet/core/funda...
    И здесь нужно заметить, что никто не мешает просто запустить новый поток самостоятельно, но это не штатная работа и чревата всё теми же последствиями какие описаны в том блоге.
    3. Режим stand alon более простой. Это отдельное консольное NET-приложение, в котором внутри работает HTTP-сервер Kestrel. Но в сравнении с IIS я бы назвал его "недосервер", т к у него мало того что нет большей части функций IIS, так ещё и хромает документация. Но всё равно, даже несмотря на это он во многом лучше IIS по причине своей простоты. Кроме того он является безальтернативным решением, если ваше приложение должно работать в docker-контейнере или на ОС отличной от Windows, где IIS не завезли пока. Т к это отдельное приложение, там можно запустить сколько угодно потоков и это не должно привести к описанным проблемам. Но всё равно лучше использовать штатные средства. Хотя бы в целях переносимости приложения между IIS и stand alone режимами.
    Ответ написан
    1 комментарий
  • Как обойти систему верификации при автоматизированной регистрации аккаунта?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    можно также автоматически заходить на указанную почту, в которую пришло письмо с кодом, парсить его оттуда и вставлять в поле при регистрации

    Это имеет смысл делать, если тестируете саму регистрацию. В других тестах есть несколько вариантов в зависимости от того где и на какой базе происходит прогон тестов (очевидно, это функциональные или интеграционные тесты, раз речь идёт о сторонней почте) Если тесты прогоняются на игрушечной базе, пустой базе или каком-то стэйдж, который достаточно закрыт от внешнего мира, то вы можете деплоить туда доп. модуль, который будет содержать апи регистрации без проверки кода из почты. На продакшен этот модуль деплоиться не будет и он должен быть сделан так, что бы безболезненно отрезаться от приложения не нарушая его функционал (и естественно с учётом требований безопасности) Разумеется, это только для тестов, которые саму по себе регистрацию не проверяют, но для них необходим свежий зарегистрированный пользователь.
    Если же тесты гоняются на проде, то очевидно этот способ не подходит и остаётся либо заранее зарегистрированный пользователь всегда один и тот же. Либо каждый раз регистрировать ящик и потом его проверять.
    Ответ написан
    Комментировать